|
|
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 root 13:
14: #include <asm/segment.h>
15: #include <asm/system.h>
16:
17: #include <sys/stat.h>
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;
123: else
124: add_wait(&tty->secondary->proc_list, wait);
125: else if (inode->i_pipe)
1.1.1.2 root 126: if (!PIPE_EMPTY(*inode) || inode->i_count < 2)
1.1 root 127: return 1;
128: else
129: add_wait(&inode->i_wait, wait);
1.1.1.4 ! root 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);
1.1 root 135: return 0;
136: }
137:
1.1.1.2 root 138: static int check_out(select_table * wait, struct inode * inode)
1.1 root 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);
1.1.1.4 ! root 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);
1.1 root 157: return 0;
158: }
159:
1.1.1.2 root 160: static int check_ex(select_table * wait, struct inode * inode)
1.1 root 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);
1.1.1.4 ! root 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);
1.1 root 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;
1.1.1.4 ! root 204: if (S_ISSOCK(current->filp[i]->f_inode->i_mode))
! 205: continue;
1.1 root 206: return -EBADF;
207: }
208: repeat:
209: wait_table.nr = 0;
1.1.1.3 root 210: wait_table.woken = 0;
211: wait_table.current = current;
212: wait_table.next_table = sel_tables;
213: sel_tables = &wait_table;
1.1 root 214: *inp = *outp = *exp = 0;
215: count = 0;
1.1.1.4 ! root 216: current->state = TASK_INTERRUPTIBLE;
1.1 root 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) &&
1.1.1.2 root 236: current->timeout && !count) {
1.1 root 237: schedule();
238: free_wait(&wait_table);
239: goto repeat;
240: }
241: free_wait(&wait_table);
1.1.1.4 ! root 242: current->state = TASK_RUNNING;
1.1 root 243: return count;
244: }
245:
246: /*
247: * Note that we cannot return -ERESTARTSYS, as we change our input
248: * parameters. Sad, but there you are. We could do some tweaking in
249: * the library function ...
250: */
251: int sys_select( unsigned long *buffer )
252: {
253: /* Perform the select(nd, in, out, ex, tv) system call. */
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:
1.1.1.2 root 262: mask = get_fs_long(buffer++);
263: if (mask >= 32)
264: mask = ~0;
265: else
266: mask = ~((~0) << mask);
1.1 root 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: }
1.1.1.3 root 312: if (i)
313: return i;
314: if (current->signal & ~current->blocked)
1.1 root 315: return -EINTR;
1.1.1.3 root 316: return 0;
1.1 root 317: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.