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