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