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 #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  *
  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.
  33  */
  34 
  35 static void free_wait(select_table * p)
     /* [previous][next][first][last][top][bottom][index][help] */
  36 {
  37         struct select_table_entry * entry = p->entry + p->nr;
  38 
  39         while (p->nr > 0) {
  40                 p->nr--;
  41                 entry--;
  42                 remove_wait_queue(entry->wait_address,&entry->wait);
  43         }
  44 }
  45 
  46 /*
  47  * The check_XX functions check out a file. We know it's either
  48  * a pipe, a character device or a fifo
  49  */
  50 static int check_in(select_table * wait, struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
  51 {
  52         if (file->f_op && file->f_op->select)
  53                 return file->f_op->select(inode,file,SEL_IN,wait);
  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         return 0;
  62 }
  63 
  64 static int check_ex(select_table * wait, struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
  65 {
  66         if (file->f_op && file->f_op->select)
  67                 return file->f_op->select(inode,file,SEL_EX,wait);
  68         return 0;
  69 }
  70 
  71 int do_select(fd_set in, fd_set out, fd_set ex,
     /* [previous][next][first][last][top][bottom][index][help] */
  72         fd_set *inp, fd_set *outp, fd_set *exp)
  73 {
  74         int count;
  75         select_table wait_table;
  76         struct file * file;
  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;
  94                 if (S_ISSOCK(current->filp[i]->f_inode->i_mode))
  95                         continue;
  96                 return -EBADF;
  97         }
  98 repeat:
  99         wait_table.nr = 0;
 100         *inp = *outp = *exp = 0;
 101         count = 0;
 102         current->state = TASK_INTERRUPTIBLE;
 103         mask = 1;
 104         for (i = 0 ; i < NR_OPEN ; i++, mask += mask) {
 105                 file = current->filp[i];
 106                 if (mask & in)
 107                         if (check_in(&wait_table,file->f_inode,file)) {
 108                                 *inp |= mask;
 109                                 count++;
 110                         }
 111                 if (mask & out)
 112                         if (check_out(&wait_table,file->f_inode,file)) {
 113                                 *outp |= mask;
 114                                 count++;
 115                         }
 116                 if (mask & ex)
 117                         if (check_ex(&wait_table,file->f_inode,file)) {
 118                                 *exp |= mask;
 119                                 count++;
 120                         }
 121         }
 122         if (!(current->signal & ~current->blocked) &&
 123             current->timeout && !count) {
 124                 schedule();
 125                 free_wait(&wait_table);
 126                 goto repeat;
 127         }
 128         free_wait(&wait_table);
 129         current->state = TASK_RUNNING;
 130         return count;
 131 }
 132 
 133 /*
 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.
 137  */
 138 int sys_select( unsigned long *buffer )
     /* [previous][next][first][last][top][bottom][index][help] */
 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 
 149         mask = get_fs_long(buffer++);
 150         if (mask >= 32)
 151                 mask = ~0;
 152         else
 153                 mask = ~((~0) << mask);
 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;
 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         }
 185         if (i < 0)
 186                 return i;
 187         if (!i && (current->signal & ~current->blocked))
 188                 return -EINTR;
 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         }
 201         return i;
 202 }

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