This source file includes following definitions.
- add_wait
- free_one_table
- free_wait
- get_tty
- check_in
- check_out
- check_ex
- do_select
- sys_select
1
2
3
4
5
6
7
8 #include <linux/fs.h>
9 #include <linux/kernel.h>
10 #include <linux/tty.h>
11 #include <linux/sched.h>
12 #include <linux/string.h>
13
14 #include <asm/segment.h>
15 #include <asm/system.h>
16
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #include <sys/time.h>
20
21 #include <const.h>
22 #include <errno.h>
23 #include <signal.h>
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 static select_table * sel_tables = NULL;
39
40 static void add_wait(struct task_struct ** wait_address, select_table * p)
41 {
42 int i;
43
44 if (!wait_address)
45 return;
46 for (i = 0 ; i < p->nr ; i++)
47 if (p->entry[i].wait_address == wait_address)
48 return;
49 current->next_wait = NULL;
50 p->entry[p->nr].wait_address = wait_address;
51 p->entry[p->nr].old_task = *wait_address;
52 *wait_address = current;
53 p->nr++;
54 }
55
56
57
58
59
60 static void free_one_table(select_table * p)
61 {
62 int i;
63 struct task_struct ** tpp;
64
65 for(tpp = &LAST_TASK ; tpp > &FIRST_TASK ; --tpp)
66 if (*tpp && ((*tpp)->next_wait == p->current))
67 (*tpp)->next_wait = NULL;
68 if (!p->nr)
69 return;
70 for (i = 0; i < p->nr ; i++) {
71 wake_up(p->entry[i].wait_address);
72 wake_up(&p->entry[i].old_task);
73 }
74 p->nr = 0;
75 }
76
77 static void free_wait(select_table * p)
78 {
79 select_table * tmp;
80
81 if (p->woken)
82 return;
83 p = sel_tables;
84 sel_tables = NULL;
85 while (p) {
86 wake_up(&p->current);
87 p->woken = 1;
88 tmp = p->next_table;
89 p->next_table = NULL;
90 free_one_table(p);
91 p = tmp;
92 }
93 }
94
95 static struct tty_struct * get_tty(struct inode * inode)
96 {
97 int major, minor;
98
99 if (!S_ISCHR(inode->i_mode))
100 return NULL;
101 if ((major = MAJOR(inode->i_rdev)) != 5 && major != 4)
102 return NULL;
103 if (major == 5)
104 minor = current->tty;
105 else
106 minor = MINOR(inode->i_rdev);
107 if (minor < 0)
108 return NULL;
109 return TTY_TABLE(minor);
110 }
111
112
113
114
115
116 static int check_in(select_table * wait, struct inode * inode)
117 {
118 struct tty_struct * tty;
119
120 if (tty = get_tty(inode))
121 if (!EMPTY(tty->secondary))
122 return 1;
123 else
124 add_wait(&tty->secondary->proc_list, wait);
125 else if (inode->i_pipe)
126 if (!PIPE_EMPTY(*inode) || inode->i_count < 2)
127 return 1;
128 else
129 add_wait(&inode->i_wait, wait);
130 else if (S_ISSOCK(inode->i_mode))
131 if (sock_select(inode, NULL, SEL_IN, wait))
132 return 1;
133 else
134 add_wait(&inode->i_wait, wait);
135 return 0;
136 }
137
138 static int check_out(select_table * wait, struct inode * inode)
139 {
140 struct tty_struct * tty;
141
142 if (tty = get_tty(inode))
143 if (!FULL(tty->write_q))
144 return 1;
145 else
146 add_wait(&tty->write_q->proc_list, wait);
147 else if (inode->i_pipe)
148 if (!PIPE_FULL(*inode))
149 return 1;
150 else
151 add_wait(&inode->i_wait, wait);
152 else if (S_ISSOCK(inode->i_mode))
153 if (sock_select(inode, NULL, SEL_OUT, wait))
154 return 1;
155 else
156 add_wait(&inode->i_wait, wait);
157 return 0;
158 }
159
160 static int check_ex(select_table * wait, struct inode * inode)
161 {
162 struct tty_struct * tty;
163
164 if (tty = get_tty(inode))
165 if (!FULL(tty->write_q))
166 return 0;
167 else
168 return 0;
169 else if (inode->i_pipe)
170 if (inode->i_count < 2)
171 return 1;
172 else
173 add_wait(&inode->i_wait,wait);
174 else if (S_ISSOCK(inode->i_mode))
175 if (sock_select(inode, NULL, SEL_EX, wait))
176 return 1;
177 else
178 add_wait(&inode->i_wait, wait);
179 return 0;
180 }
181
182 int do_select(fd_set in, fd_set out, fd_set ex,
183 fd_set *inp, fd_set *outp, fd_set *exp)
184 {
185 int count;
186 select_table wait_table;
187 int i;
188 fd_set mask;
189
190 mask = in | out | ex;
191 for (i = 0 ; i < NR_OPEN ; i++,mask >>= 1) {
192 if (!(mask & 1))
193 continue;
194 if (!current->filp[i])
195 return -EBADF;
196 if (!current->filp[i]->f_inode)
197 return -EBADF;
198 if (current->filp[i]->f_inode->i_pipe)
199 continue;
200 if (S_ISCHR(current->filp[i]->f_inode->i_mode))
201 continue;
202 if (S_ISFIFO(current->filp[i]->f_inode->i_mode))
203 continue;
204 if (S_ISSOCK(current->filp[i]->f_inode->i_mode))
205 continue;
206 return -EBADF;
207 }
208 repeat:
209 wait_table.nr = 0;
210 wait_table.woken = 0;
211 wait_table.current = current;
212 wait_table.next_table = sel_tables;
213 sel_tables = &wait_table;
214 *inp = *outp = *exp = 0;
215 count = 0;
216 current->state = TASK_INTERRUPTIBLE;
217 mask = 1;
218 for (i = 0 ; i < NR_OPEN ; i++, mask += mask) {
219 if (mask & in)
220 if (check_in(&wait_table,current->filp[i]->f_inode)) {
221 *inp |= mask;
222 count++;
223 }
224 if (mask & out)
225 if (check_out(&wait_table,current->filp[i]->f_inode)) {
226 *outp |= mask;
227 count++;
228 }
229 if (mask & ex)
230 if (check_ex(&wait_table,current->filp[i]->f_inode)) {
231 *exp |= mask;
232 count++;
233 }
234 }
235 if (!(current->signal & ~current->blocked) &&
236 current->timeout && !count) {
237 schedule();
238 free_wait(&wait_table);
239 goto repeat;
240 }
241 free_wait(&wait_table);
242 current->state = TASK_RUNNING;
243 return count;
244 }
245
246
247
248
249
250
251 int sys_select( unsigned long *buffer )
252 {
253
254 int i;
255 fd_set res_in, in = 0, *inp;
256 fd_set res_out, out = 0, *outp;
257 fd_set res_ex, ex = 0, *exp;
258 fd_set mask;
259 struct timeval *tvp;
260 unsigned long timeout;
261
262 mask = get_fs_long(buffer++);
263 if (mask >= 32)
264 mask = ~0;
265 else
266 mask = ~((~0) << mask);
267 inp = (fd_set *) get_fs_long(buffer++);
268 outp = (fd_set *) get_fs_long(buffer++);
269 exp = (fd_set *) get_fs_long(buffer++);
270 tvp = (struct timeval *) get_fs_long(buffer);
271
272 if (inp)
273 in = mask & get_fs_long(inp);
274 if (outp)
275 out = mask & get_fs_long(outp);
276 if (exp)
277 ex = mask & get_fs_long(exp);
278 timeout = 0xffffffff;
279 if (tvp) {
280 timeout = get_fs_long((unsigned long *)&tvp->tv_usec)/(1000000/HZ);
281 timeout += get_fs_long((unsigned long *)&tvp->tv_sec) * HZ;
282 timeout += jiffies;
283 }
284 current->timeout = timeout;
285 i = do_select(in, out, ex, &res_in, &res_out, &res_ex);
286 if (current->timeout > jiffies)
287 timeout = current->timeout - jiffies;
288 else
289 timeout = 0;
290 current->timeout = 0;
291 if (i < 0)
292 return i;
293 if (inp) {
294 verify_area(inp, 4);
295 put_fs_long(res_in,inp);
296 }
297 if (outp) {
298 verify_area(outp,4);
299 put_fs_long(res_out,outp);
300 }
301 if (exp) {
302 verify_area(exp,4);
303 put_fs_long(res_ex,exp);
304 }
305 if (tvp) {
306 verify_area(tvp, sizeof(*tvp));
307 put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec);
308 timeout %= HZ;
309 timeout *= (1000000/HZ);
310 put_fs_long(timeout, (unsigned long *) &tvp->tv_usec);
311 }
312 if (i)
313 return i;
314 if (current->signal & ~current->blocked)
315 return -EINTR;
316 return 0;
317 }