Annotation of linux/fs/select.c, revision 1.1.1.7

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.