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