root/fs/select.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. free_wait
  2. check_in
  3. check_out
  4. check_ex
  5. do_select
  6. sys_select

   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/types.h>
   9 #include <linux/time.h>
  10 #include <linux/fs.h>
  11 #include <linux/kernel.h>
  12 #include <linux/sched.h>
  13 #include <linux/string.h>
  14 #include <linux/stat.h>
  15 #include <linux/signal.h>
  16 #include <linux/errno.h>
  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  *
  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.
  31  */
  32 
  33 static void free_wait(select_table * p)
     /* [previous][next][first][last][top][bottom][index][help] */
  34 {
  35         struct select_table_entry * entry = p->entry + p->nr;
  36 
  37         while (p->nr > 0) {
  38                 p->nr--;
  39                 entry--;
  40                 remove_wait_queue(entry->wait_address,&entry->wait);
  41         }
  42 }
  43 
  44 /*
  45  * The check_XX functions check out a file. We know it's either
  46  * a pipe, a character device or a fifo
  47  */
  48 static int check_in(select_table * wait, struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
  49 {
  50         if (file->f_op && file->f_op->select)
  51                 return file->f_op->select(inode,file,SEL_IN,wait);
  52         if (inode && S_ISREG(inode->i_mode))
  53                 return 1;
  54         return 0;
  55 }
  56 
  57 static int check_out(select_table * wait, struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
  58 {
  59         if (file->f_op && file->f_op->select)
  60                 return file->f_op->select(inode,file,SEL_OUT,wait);
  61         if (inode && S_ISREG(inode->i_mode))
  62                 return 1;
  63         return 0;
  64 }
  65 
  66 static int check_ex(select_table * wait, struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
  67 {
  68         if (file->f_op && file->f_op->select)
  69                 return file->f_op->select(inode,file,SEL_EX,wait);
  70         if (inode && S_ISREG(inode->i_mode))
  71                 return 1;
  72         return 0;
  73 }
  74 
  75 int do_select(fd_set in, fd_set out, fd_set ex,
     /* [previous][next][first][last][top][bottom][index][help] */
  76         fd_set *inp, fd_set *outp, fd_set *exp)
  77 {
  78         int count;
  79         select_table wait_table;
  80         struct file * file;
  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;
  97         current->state = TASK_INTERRUPTIBLE;
  98         mask = 1;
  99         for (i = 0 ; i < NR_OPEN ; i++, mask += mask) {
 100                 file = current->filp[i];
 101                 if (mask & in)
 102                         if (check_in(&wait_table,file->f_inode,file)) {
 103                                 *inp |= mask;
 104                                 count++;
 105                         }
 106                 if (mask & out)
 107                         if (check_out(&wait_table,file->f_inode,file)) {
 108                                 *outp |= mask;
 109                                 count++;
 110                         }
 111                 if (mask & ex)
 112                         if (check_ex(&wait_table,file->f_inode,file)) {
 113                                 *exp |= mask;
 114                                 count++;
 115                         }
 116         }
 117         if (!(current->signal & ~current->blocked) &&
 118             current->timeout && !count) {
 119                 schedule();
 120                 free_wait(&wait_table);
 121                 goto repeat;
 122         }
 123         free_wait(&wait_table);
 124         current->state = TASK_RUNNING;
 125         return count;
 126 }
 127 
 128 /*
 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.
 132  */
 133 int sys_select( unsigned long *buffer )
     /* [previous][next][first][last][top][bottom][index][help] */
 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 
 144         mask = get_fs_long(buffer++);
 145         if (mask >= 32)
 146                 mask = ~0;
 147         else
 148                 mask = ~((~0) << mask);
 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;
 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         }
 180         if (i < 0)
 181                 return i;
 182         if (!i && (current->signal & ~current->blocked))
 183                 return -EINTR;
 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         }
 196         return i;
 197 }

/* [previous][next][first][last][top][bottom][index][help] */