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