|
|
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:
1.1.1.7 ! root 8: #include <linux/types.h>
! 9: #include <linux/time.h>
1.1 root 10: #include <linux/fs.h>
11: #include <linux/kernel.h>
12: #include <linux/sched.h>
1.1.1.4 root 13: #include <linux/string.h>
1.1.1.5 root 14: #include <linux/stat.h>
1.1.1.7 ! root 15: #include <linux/signal.h>
! 16: #include <linux/errno.h>
1.1 root 17:
18: #include <asm/segment.h>
19: #include <asm/system.h>
20:
21: #include <const.h>
22:
23: /*
24: * Ok, Peter made a complicated, but straightforward multiple_wait() function.
25: * I have rewritten this, taking some shortcuts: This code may not be easy to
26: * follow, but it should be free of race-conditions, and it's practical. If you
27: * understand what I'm doing here, then you understand how the linux sleep/wakeup
28: * mechanism works.
29: *
1.1.1.7 ! root 30: * Two very simple procedures, select_wait() and free_wait() make all the work.
! 31: * select_wait() is a inline-function defined in <linux/fs.h>, as all select
! 32: * functions have to call it to add an entry to the select table.
1.1 root 33: */
34:
1.1.1.3 root 35: static void free_wait(select_table * p)
36: {
1.1.1.7 ! root 37: struct select_table_entry * entry = p->entry + p->nr;
1.1.1.3 root 38:
1.1.1.7 ! root 39: while (p->nr > 0) {
! 40: p->nr--;
! 41: entry--;
! 42: remove_wait_queue(entry->wait_address,&entry->wait);
1.1.1.3 root 43: }
44: }
45:
1.1 root 46: /*
47: * The check_XX functions check out a file. We know it's either
1.1.1.7 ! root 48: * a pipe, a character device or a fifo
1.1 root 49: */
1.1.1.7 ! root 50: static int check_in(select_table * wait, struct inode * inode, struct file * file)
1.1 root 51: {
1.1.1.7 ! root 52: if (file->f_op && file->f_op->select)
! 53: return file->f_op->select(inode,file,SEL_IN,wait);
1.1 root 54: return 0;
55: }
56:
1.1.1.7 ! root 57: static int check_out(select_table * wait, struct inode * inode, struct file * file)
1.1 root 58: {
1.1.1.7 ! root 59: if (file->f_op && file->f_op->select)
! 60: return file->f_op->select(inode,file,SEL_OUT,wait);
1.1 root 61: return 0;
62: }
63:
1.1.1.7 ! root 64: static int check_ex(select_table * wait, struct inode * inode, struct file * file)
1.1 root 65: {
1.1.1.7 ! root 66: if (file->f_op && file->f_op->select)
! 67: return file->f_op->select(inode,file,SEL_EX,wait);
1.1 root 68: return 0;
69: }
70:
71: int do_select(fd_set in, fd_set out, fd_set ex,
72: fd_set *inp, fd_set *outp, fd_set *exp)
73: {
74: int count;
75: select_table wait_table;
1.1.1.7 ! root 76: struct file * file;
1.1 root 77: int i;
78: fd_set mask;
79:
80: mask = in | out | ex;
81: for (i = 0 ; i < NR_OPEN ; i++,mask >>= 1) {
82: if (!(mask & 1))
83: continue;
84: if (!current->filp[i])
85: return -EBADF;
86: if (!current->filp[i]->f_inode)
87: return -EBADF;
88: if (current->filp[i]->f_inode->i_pipe)
89: continue;
90: if (S_ISCHR(current->filp[i]->f_inode->i_mode))
91: continue;
92: if (S_ISFIFO(current->filp[i]->f_inode->i_mode))
93: continue;
1.1.1.4 root 94: if (S_ISSOCK(current->filp[i]->f_inode->i_mode))
95: continue;
1.1 root 96: return -EBADF;
97: }
98: repeat:
99: wait_table.nr = 0;
100: *inp = *outp = *exp = 0;
101: count = 0;
1.1.1.4 root 102: current->state = TASK_INTERRUPTIBLE;
1.1 root 103: mask = 1;
104: for (i = 0 ; i < NR_OPEN ; i++, mask += mask) {
1.1.1.7 ! root 105: file = current->filp[i];
1.1 root 106: if (mask & in)
1.1.1.7 ! root 107: if (check_in(&wait_table,file->f_inode,file)) {
1.1 root 108: *inp |= mask;
109: count++;
110: }
111: if (mask & out)
1.1.1.7 ! root 112: if (check_out(&wait_table,file->f_inode,file)) {
1.1 root 113: *outp |= mask;
114: count++;
115: }
116: if (mask & ex)
1.1.1.7 ! root 117: if (check_ex(&wait_table,file->f_inode,file)) {
1.1 root 118: *exp |= mask;
119: count++;
120: }
121: }
122: if (!(current->signal & ~current->blocked) &&
1.1.1.2 root 123: current->timeout && !count) {
1.1 root 124: schedule();
125: free_wait(&wait_table);
126: goto repeat;
127: }
128: free_wait(&wait_table);
1.1.1.4 root 129: current->state = TASK_RUNNING;
1.1 root 130: return count;
131: }
132:
133: /*
1.1.1.7 ! root 134: * We can actually return ERESTARTSYS insetad of EINTR, but I'd
! 135: * like to be certain this leads to no problems. So I return
! 136: * EINTR just for safety.
1.1 root 137: */
138: int sys_select( unsigned long *buffer )
139: {
140: /* Perform the select(nd, in, out, ex, tv) system call. */
141: int i;
142: fd_set res_in, in = 0, *inp;
143: fd_set res_out, out = 0, *outp;
144: fd_set res_ex, ex = 0, *exp;
145: fd_set mask;
146: struct timeval *tvp;
147: unsigned long timeout;
148:
1.1.1.2 root 149: mask = get_fs_long(buffer++);
150: if (mask >= 32)
151: mask = ~0;
152: else
153: mask = ~((~0) << mask);
1.1 root 154: inp = (fd_set *) get_fs_long(buffer++);
155: outp = (fd_set *) get_fs_long(buffer++);
156: exp = (fd_set *) get_fs_long(buffer++);
157: tvp = (struct timeval *) get_fs_long(buffer);
158:
159: if (inp)
160: in = mask & get_fs_long(inp);
161: if (outp)
162: out = mask & get_fs_long(outp);
163: if (exp)
164: ex = mask & get_fs_long(exp);
165: timeout = 0xffffffff;
166: if (tvp) {
167: timeout = get_fs_long((unsigned long *)&tvp->tv_usec)/(1000000/HZ);
168: timeout += get_fs_long((unsigned long *)&tvp->tv_sec) * HZ;
169: timeout += jiffies;
170: }
171: current->timeout = timeout;
172: i = do_select(in, out, ex, &res_in, &res_out, &res_ex);
173: if (current->timeout > jiffies)
174: timeout = current->timeout - jiffies;
175: else
176: timeout = 0;
177: current->timeout = 0;
1.1.1.7 ! root 178: if (tvp) {
! 179: verify_area(tvp, sizeof(*tvp));
! 180: put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec);
! 181: timeout %= HZ;
! 182: timeout *= (1000000/HZ);
! 183: put_fs_long(timeout, (unsigned long *) &tvp->tv_usec);
! 184: }
1.1 root 185: if (i < 0)
186: return i;
1.1.1.7 ! root 187: if (!i && (current->signal & ~current->blocked))
! 188: return -EINTR;
1.1 root 189: if (inp) {
190: verify_area(inp, 4);
191: put_fs_long(res_in,inp);
192: }
193: if (outp) {
194: verify_area(outp,4);
195: put_fs_long(res_out,outp);
196: }
197: if (exp) {
198: verify_area(exp,4);
199: put_fs_long(res_ex,exp);
200: }
1.1.1.7 ! root 201: return i;
1.1 root 202: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.