This source file includes following definitions.
- free_wait
- check
- do_select
- __get_fd_set
- __set_fd_set
- sys_select
1
2
3
4
5
6
7
8 #include <linux/types.h>
9 #include <linux/time.h>
10 #include <linux/fs.h>
11 #include <linux/kernel.h>
12 #include <linux/sched.h>
13 #include <linux/string.h>
14 #include <linux/stat.h>
15 #include <linux/signal.h>
16 #include <linux/errno.h>
17
18 #include <asm/segment.h>
19 #include <asm/system.h>
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 static void free_wait(select_table * p)
40 {
41 struct select_table_entry * entry = p->entry + p->nr;
42
43 while (p->nr > 0) {
44 p->nr--;
45 entry--;
46 remove_wait_queue(entry->wait_address,&entry->wait);
47 }
48 }
49
50
51
52
53
54
55
56
57
58
59
60
61 static int check(int flag, select_table * wait, struct file * file)
62 {
63 struct inode * inode;
64 struct file_operations *fops;
65 int (*select) (struct inode *, struct file *, int, select_table *);
66
67 inode = file->f_inode;
68 if ((fops = file->f_op) && (select = fops->select))
69 return select(inode, file, flag, wait)
70 || (wait && select(inode, file, flag, NULL));
71 if (S_ISREG(inode->i_mode))
72 return 1;
73 return 0;
74 }
75
76 int do_select(int n, fd_set *in, fd_set *out, fd_set *ex,
77 fd_set *res_in, fd_set *res_out, fd_set *res_ex)
78 {
79 int count;
80 select_table wait_table, *wait;
81 struct select_table_entry *entry;
82 int i;
83 int max;
84
85 max = -1;
86 for (i = 0 ; i < n ; i++) {
87 if (!FD_ISSET(i, in) &&
88 !FD_ISSET(i, out) &&
89 !FD_ISSET(i, ex))
90 continue;
91 if (!current->filp[i])
92 return -EBADF;
93 if (!current->filp[i]->f_inode)
94 return -EBADF;
95 max = i;
96 }
97 n = max + 1;
98 entry = (struct select_table_entry *) get_free_page(GFP_KERNEL);
99 if (!entry)
100 return -ENOMEM;
101 FD_ZERO(res_in);
102 FD_ZERO(res_out);
103 FD_ZERO(res_ex);
104 count = 0;
105 wait_table.nr = 0;
106 wait_table.entry = entry;
107 wait = &wait_table;
108 repeat:
109 current->state = TASK_INTERRUPTIBLE;
110 for (i = 0 ; i < n ; i++) {
111 if (FD_ISSET(i,in) && check(SEL_IN,wait,current->filp[i])) {
112 FD_SET(i, res_in);
113 count++;
114 wait = NULL;
115 }
116 if (FD_ISSET(i,out) && check(SEL_OUT,wait,current->filp[i])) {
117 FD_SET(i, res_out);
118 count++;
119 wait = NULL;
120 }
121 if (FD_ISSET(i,ex) && check(SEL_EX,wait,current->filp[i])) {
122 FD_SET(i, res_ex);
123 count++;
124 wait = NULL;
125 }
126 }
127 wait = NULL;
128 if (!count && current->timeout && !(current->signal & ~current->blocked)) {
129 schedule();
130 goto repeat;
131 }
132 free_wait(&wait_table);
133 free_page((unsigned long) entry);
134 current->state = TASK_RUNNING;
135 return count;
136 }
137
138 static void __get_fd_set(int nr, unsigned long * fs_pointer, unsigned long * fdset)
139 {
140 FD_ZERO(fdset);
141 if (!fs_pointer)
142 return;
143 while (nr > 0) {
144 *fdset = get_fs_long(fs_pointer);
145 fdset++;
146 fs_pointer++;
147 nr -= 32;
148 }
149 }
150
151 static void __set_fd_set(int nr, unsigned long * fs_pointer, unsigned long * fdset)
152 {
153 if (!fs_pointer)
154 return;
155 verify_area(fs_pointer, sizeof(fd_set));
156 while (nr > 0) {
157 put_fs_long(*fdset, fs_pointer);
158 fdset++;
159 fs_pointer++;
160 nr -= 32;
161 }
162 }
163
164 #define get_fd_set(nr,fsp,fdp) \
165 __get_fd_set(nr, (unsigned long *) (fsp), (unsigned long *) (fdp))
166
167 #define set_fd_set(nr,fsp,fdp) \
168 __set_fd_set(nr, (unsigned long *) (fsp), (unsigned long *) (fdp))
169
170
171
172
173
174
175 int sys_select( unsigned long *buffer )
176 {
177
178 int i;
179 fd_set res_in, in, *inp;
180 fd_set res_out, out, *outp;
181 fd_set res_ex, ex, *exp;
182 int n;
183 struct timeval *tvp;
184 unsigned long timeout;
185
186 n = get_fs_long(buffer++);
187 if (n < 0)
188 return -EINVAL;
189 if (n > NR_OPEN)
190 n = NR_OPEN;
191 inp = (fd_set *) get_fs_long(buffer++);
192 outp = (fd_set *) get_fs_long(buffer++);
193 exp = (fd_set *) get_fs_long(buffer++);
194 tvp = (struct timeval *) get_fs_long(buffer);
195 get_fd_set(n, inp, &in);
196 get_fd_set(n, outp, &out);
197 get_fd_set(n, exp, &ex);
198 timeout = 0xffffffff;
199 if (tvp) {
200 timeout = jiffies;
201 timeout += get_fs_long((unsigned long *)&tvp->tv_usec)/(1000000/HZ);
202 timeout += get_fs_long((unsigned long *)&tvp->tv_sec) * HZ;
203 if (timeout <= jiffies)
204 timeout = 0;
205 }
206 current->timeout = timeout;
207 i = do_select(n, &in, &out, &ex, &res_in, &res_out, &res_ex);
208 if (current->timeout > jiffies)
209 timeout = current->timeout - jiffies;
210 else
211 timeout = 0;
212 current->timeout = 0;
213 if (tvp) {
214 verify_area(tvp, sizeof(*tvp));
215 put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec);
216 timeout %= HZ;
217 timeout *= (1000000/HZ);
218 put_fs_long(timeout, (unsigned long *) &tvp->tv_usec);
219 }
220 if (i < 0)
221 return i;
222 if (!i && (current->signal & ~current->blocked))
223 return -EINTR;
224 set_fd_set(n, inp, &res_in);
225 set_fd_set(n, outp, &res_out);
226 set_fd_set(n, exp, &res_ex);
227 return i;
228 }