|
|
1.1 root 1: /*
2: * This file contains the procedures for the handling of select
3: *
4: * Created for Linux based loosely upon Mathius Lattner's minix
5: * patches by Peter MacDonald. Heavily edited by Linus.
6: */
7:
8: #include <linux/fs.h>
9: #include <linux/kernel.h>
10: #include <linux/tty.h>
11: #include <linux/sched.h>
1.1.1.4 root 12: #include <linux/string.h>
1.1.1.5 root 13: #include <linux/stat.h>
1.1 root 14:
15: #include <asm/segment.h>
16: #include <asm/system.h>
17:
18: #include <sys/types.h>
1.1.1.4 root 19: #include <sys/time.h>
20:
1.1 root 21: #include <const.h>
22: #include <errno.h>
23: #include <signal.h>
24:
25: /*
26: * Ok, Peter made a complicated, but straightforward multiple_wait() function.
27: * I have rewritten this, taking some shortcuts: This code may not be easy to
28: * follow, but it should be free of race-conditions, and it's practical. If you
29: * understand what I'm doing here, then you understand how the linux sleep/wakeup
30: * mechanism works.
31: *
32: * Two very simple procedures, add_wait() and free_wait() make all the work. We
33: * have to have interrupts disabled throughout the select, but that's not really
34: * such a loss: sleeping automatically frees interrupts when we aren't in this
35: * task.
36: */
37:
1.1.1.3 root 38: static select_table * sel_tables = NULL;
39:
1.1 root 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;
1.1.1.3 root 49: current->next_wait = NULL;
1.1 root 50: p->entry[p->nr].wait_address = wait_address;
1.1.1.3 root 51: p->entry[p->nr].old_task = *wait_address;
1.1 root 52: *wait_address = current;
53: p->nr++;
54: }
55:
1.1.1.3 root 56: /*
57: * free_wait removes the current task from any wait-queues and then
58: * wakes up the queues.
59: */
60: static void free_one_table(select_table * p)
1.1 root 61: {
62: int i;
63: struct task_struct ** tpp;
64:
1.1.1.3 root 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;
1.1 root 70: for (i = 0; i < p->nr ; i++) {
1.1.1.3 root 71: wake_up(p->entry[i].wait_address);
72: wake_up(&p->entry[i].old_task);
1.1 root 73: }
74: p->nr = 0;
75: }
76:
1.1.1.3 root 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:
1.1.1.2 root 95: static struct tty_struct * get_tty(struct inode * inode)
1.1 root 96: {
97: int major, minor;
98:
99: if (!S_ISCHR(inode->i_mode))
100: return NULL;
1.1.1.2 root 101: if ((major = MAJOR(inode->i_rdev)) != 5 && major != 4)
1.1 root 102: return NULL;
103: if (major == 5)
104: minor = current->tty;
105: else
1.1.1.2 root 106: minor = MINOR(inode->i_rdev);
1.1 root 107: if (minor < 0)
108: return NULL;
109: return TTY_TABLE(minor);
110: }
111:
112: /*
113: * The check_XX functions check out a file. We know it's either
114: * a pipe, a character device or a fifo (fifo's not implemented)
115: */
1.1.1.2 root 116: static int check_in(select_table * wait, struct inode * inode)
1.1 root 117: {
118: struct tty_struct * tty;
119:
120: if (tty = get_tty(inode))
121: if (!EMPTY(tty->secondary))
122: return 1;
1.1.1.6 ! root 123: else if (tty->link && !tty->link->count)
! 124: return 1;
1.1 root 125: else
126: add_wait(&tty->secondary->proc_list, wait);
127: else if (inode->i_pipe)
1.1.1.6 ! root 128: if (!PIPE_EMPTY(*inode) || !PIPE_WRITERS(*inode))
1.1 root 129: return 1;
130: else
131: add_wait(&inode->i_wait, wait);
1.1.1.4 root 132: else if (S_ISSOCK(inode->i_mode))
133: if (sock_select(inode, NULL, SEL_IN, wait))
134: return 1;
135: else
136: add_wait(&inode->i_wait, wait);
1.1 root 137: return 0;
138: }
139:
1.1.1.2 root 140: static int check_out(select_table * wait, struct inode * inode)
1.1 root 141: {
142: struct tty_struct * tty;
143:
144: if (tty = get_tty(inode))
145: if (!FULL(tty->write_q))
146: return 1;
147: else
148: add_wait(&tty->write_q->proc_list, wait);
149: else if (inode->i_pipe)
150: if (!PIPE_FULL(*inode))
151: return 1;
152: else
153: add_wait(&inode->i_wait, wait);
1.1.1.4 root 154: else if (S_ISSOCK(inode->i_mode))
155: if (sock_select(inode, NULL, SEL_OUT, wait))
156: return 1;
157: else
158: add_wait(&inode->i_wait, wait);
1.1 root 159: return 0;
160: }
161:
1.1.1.2 root 162: static int check_ex(select_table * wait, struct inode * inode)
1.1 root 163: {
164: struct tty_struct * tty;
165:
166: if (tty = get_tty(inode))
167: if (!FULL(tty->write_q))
168: return 0;
169: else
170: return 0;
171: else if (inode->i_pipe)
1.1.1.6 ! root 172: if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode))
1.1 root 173: return 1;
174: else
175: add_wait(&inode->i_wait,wait);
1.1.1.4 root 176: else if (S_ISSOCK(inode->i_mode))
177: if (sock_select(inode, NULL, SEL_EX, wait))
178: return 1;
179: else
180: add_wait(&inode->i_wait, wait);
1.1 root 181: return 0;
182: }
183:
184: int do_select(fd_set in, fd_set out, fd_set ex,
185: fd_set *inp, fd_set *outp, fd_set *exp)
186: {
187: int count;
188: select_table wait_table;
189: int i;
190: fd_set mask;
191:
192: mask = in | out | ex;
193: for (i = 0 ; i < NR_OPEN ; i++,mask >>= 1) {
194: if (!(mask & 1))
195: continue;
196: if (!current->filp[i])
197: return -EBADF;
198: if (!current->filp[i]->f_inode)
199: return -EBADF;
200: if (current->filp[i]->f_inode->i_pipe)
201: continue;
202: if (S_ISCHR(current->filp[i]->f_inode->i_mode))
203: continue;
204: if (S_ISFIFO(current->filp[i]->f_inode->i_mode))
205: continue;
1.1.1.4 root 206: if (S_ISSOCK(current->filp[i]->f_inode->i_mode))
207: continue;
1.1 root 208: return -EBADF;
209: }
210: repeat:
211: wait_table.nr = 0;
1.1.1.3 root 212: wait_table.woken = 0;
213: wait_table.current = current;
214: wait_table.next_table = sel_tables;
215: sel_tables = &wait_table;
1.1 root 216: *inp = *outp = *exp = 0;
217: count = 0;
1.1.1.4 root 218: current->state = TASK_INTERRUPTIBLE;
1.1 root 219: mask = 1;
220: for (i = 0 ; i < NR_OPEN ; i++, mask += mask) {
221: if (mask & in)
222: if (check_in(&wait_table,current->filp[i]->f_inode)) {
223: *inp |= mask;
224: count++;
225: }
226: if (mask & out)
227: if (check_out(&wait_table,current->filp[i]->f_inode)) {
228: *outp |= mask;
229: count++;
230: }
231: if (mask & ex)
232: if (check_ex(&wait_table,current->filp[i]->f_inode)) {
233: *exp |= mask;
234: count++;
235: }
236: }
237: if (!(current->signal & ~current->blocked) &&
1.1.1.2 root 238: current->timeout && !count) {
1.1 root 239: schedule();
240: free_wait(&wait_table);
241: goto repeat;
242: }
243: free_wait(&wait_table);
1.1.1.4 root 244: current->state = TASK_RUNNING;
1.1 root 245: return count;
246: }
247:
248: /*
249: * Note that we cannot return -ERESTARTSYS, as we change our input
250: * parameters. Sad, but there you are. We could do some tweaking in
251: * the library function ...
252: */
253: int sys_select( unsigned long *buffer )
254: {
255: /* Perform the select(nd, in, out, ex, tv) system call. */
256: int i;
257: fd_set res_in, in = 0, *inp;
258: fd_set res_out, out = 0, *outp;
259: fd_set res_ex, ex = 0, *exp;
260: fd_set mask;
261: struct timeval *tvp;
262: unsigned long timeout;
263:
1.1.1.2 root 264: mask = get_fs_long(buffer++);
265: if (mask >= 32)
266: mask = ~0;
267: else
268: mask = ~((~0) << mask);
1.1 root 269: inp = (fd_set *) get_fs_long(buffer++);
270: outp = (fd_set *) get_fs_long(buffer++);
271: exp = (fd_set *) get_fs_long(buffer++);
272: tvp = (struct timeval *) get_fs_long(buffer);
273:
274: if (inp)
275: in = mask & get_fs_long(inp);
276: if (outp)
277: out = mask & get_fs_long(outp);
278: if (exp)
279: ex = mask & get_fs_long(exp);
280: timeout = 0xffffffff;
281: if (tvp) {
282: timeout = get_fs_long((unsigned long *)&tvp->tv_usec)/(1000000/HZ);
283: timeout += get_fs_long((unsigned long *)&tvp->tv_sec) * HZ;
284: timeout += jiffies;
285: }
286: current->timeout = timeout;
287: i = do_select(in, out, ex, &res_in, &res_out, &res_ex);
288: if (current->timeout > jiffies)
289: timeout = current->timeout - jiffies;
290: else
291: timeout = 0;
292: current->timeout = 0;
293: if (i < 0)
294: return i;
295: if (inp) {
296: verify_area(inp, 4);
297: put_fs_long(res_in,inp);
298: }
299: if (outp) {
300: verify_area(outp,4);
301: put_fs_long(res_out,outp);
302: }
303: if (exp) {
304: verify_area(exp,4);
305: put_fs_long(res_ex,exp);
306: }
307: if (tvp) {
308: verify_area(tvp, sizeof(*tvp));
309: put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec);
310: timeout %= HZ;
311: timeout *= (1000000/HZ);
312: put_fs_long(timeout, (unsigned long *) &tvp->tv_usec);
313: }
1.1.1.3 root 314: if (i)
315: return i;
316: if (current->signal & ~current->blocked)
1.1 root 317: return -EINTR;
1.1.1.3 root 318: return 0;
1.1 root 319: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.