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

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: 
                      8: #include <linux/fs.h>
                      9: #include <linux/kernel.h>
                     10: #include <linux/tty.h>
                     11: #include <linux/sched.h>
                     12: 
                     13: #include <asm/segment.h>
                     14: #include <asm/system.h>
                     15: 
                     16: #include <sys/stat.h>
                     17: #include <sys/types.h>
                     18: #include <string.h>
                     19: #include <const.h>
                     20: #include <errno.h>
                     21: #include <sys/time.h>
                     22: #include <signal.h>
                     23: 
                     24: /*
                     25:  * Ok, Peter made a complicated, but straightforward multiple_wait() function.
                     26:  * I have rewritten this, taking some shortcuts: This code may not be easy to
                     27:  * follow, but it should be free of race-conditions, and it's practical. If you
                     28:  * understand what I'm doing here, then you understand how the linux sleep/wakeup
                     29:  * mechanism works.
                     30:  *
                     31:  * Two very simple procedures, add_wait() and free_wait() make all the work. We
                     32:  * have to have interrupts disabled throughout the select, but that's not really
                     33:  * such a loss: sleeping automatically frees interrupts when we aren't in this
                     34:  * task.
                     35:  */
                     36: 
                     37: typedef struct {
                     38:        struct task_struct * old_task;
                     39:        struct task_struct ** wait_address;
                     40: } wait_entry;
                     41: 
                     42: typedef struct {
                     43:        int nr;
                     44:        wait_entry entry[NR_OPEN*3];
                     45: } select_table;
                     46: 
                     47: static void add_wait(struct task_struct ** wait_address, select_table * p)
                     48: {
                     49:        int i;
                     50: 
                     51:        if (!wait_address)
                     52:                return;
                     53:        for (i = 0 ; i < p->nr ; i++)
                     54:                if (p->entry[i].wait_address == wait_address)
                     55:                        return;
                     56:        p->entry[p->nr].wait_address = wait_address;
                     57:        p->entry[p->nr].old_task = * wait_address;
                     58:        *wait_address = current;
                     59:        p->nr++;
                     60: }
                     61: 
                     62: static void free_wait(select_table * p)
                     63: {
                     64:        int i;
                     65:        struct task_struct ** tpp;
                     66: 
                     67:        for (i = 0; i < p->nr ; i++) {
                     68:                tpp = p->entry[i].wait_address;
                     69:                while (*tpp && *tpp != current) {
                     70:                        (*tpp)->state = 0;
                     71:                        current->state = TASK_UNINTERRUPTIBLE;
                     72:                        schedule();
                     73:                }
                     74:                if (!*tpp)
                     75:                        printk("free_wait: NULL");
                     76:                if (*tpp = p->entry[i].old_task)
                     77:                        (**tpp).state = 0;
                     78:        }
                     79:        p->nr = 0;
                     80: }
                     81: 
1.1.1.2 ! root       82: static struct tty_struct * get_tty(struct inode * inode)
1.1       root       83: {
                     84:        int major, minor;
                     85: 
                     86:        if (!S_ISCHR(inode->i_mode))
                     87:                return NULL;
1.1.1.2 ! root       88:        if ((major = MAJOR(inode->i_rdev)) != 5 && major != 4)
1.1       root       89:                return NULL;
                     90:        if (major == 5)
                     91:                minor = current->tty;
                     92:        else
1.1.1.2 ! root       93:                minor = MINOR(inode->i_rdev);
1.1       root       94:        if (minor < 0)
                     95:                return NULL;
                     96:        return TTY_TABLE(minor);
                     97: }
                     98: 
                     99: /*
                    100:  * The check_XX functions check out a file. We know it's either
                    101:  * a pipe, a character device or a fifo (fifo's not implemented)
                    102:  */
1.1.1.2 ! root      103: static int check_in(select_table * wait, struct inode * inode)
1.1       root      104: {
                    105:        struct tty_struct * tty;
                    106: 
                    107:        if (tty = get_tty(inode))
                    108:                if (!EMPTY(tty->secondary))
                    109:                        return 1;
                    110:                else
                    111:                        add_wait(&tty->secondary->proc_list, wait);
                    112:        else if (inode->i_pipe)
1.1.1.2 ! root      113:                if (!PIPE_EMPTY(*inode) || inode->i_count < 2)
1.1       root      114:                        return 1;
                    115:                else
                    116:                        add_wait(&inode->i_wait, wait);
                    117:        return 0;
                    118: }
                    119: 
1.1.1.2 ! root      120: static int check_out(select_table * wait, struct inode * inode)
1.1       root      121: {
                    122:        struct tty_struct * tty;
                    123: 
                    124:        if (tty = get_tty(inode))
                    125:                if (!FULL(tty->write_q))
                    126:                        return 1;
                    127:                else
                    128:                        add_wait(&tty->write_q->proc_list, wait);
                    129:        else if (inode->i_pipe)
                    130:                if (!PIPE_FULL(*inode))
                    131:                        return 1;
                    132:                else
                    133:                        add_wait(&inode->i_wait, wait);
                    134:        return 0;
                    135: }
                    136: 
1.1.1.2 ! root      137: static int check_ex(select_table * wait, struct inode * inode)
1.1       root      138: {
                    139:        struct tty_struct * tty;
                    140: 
                    141:        if (tty = get_tty(inode))
                    142:                if (!FULL(tty->write_q))
                    143:                        return 0;
                    144:                else
                    145:                        return 0;
                    146:        else if (inode->i_pipe)
                    147:                if (inode->i_count < 2)
                    148:                        return 1;
                    149:                else
                    150:                        add_wait(&inode->i_wait,wait);
                    151:        return 0;
                    152: }
                    153: 
                    154: int do_select(fd_set in, fd_set out, fd_set ex,
                    155:        fd_set *inp, fd_set *outp, fd_set *exp)
                    156: {
                    157:        int count;
                    158:        select_table wait_table;
                    159:        int i;
                    160:        fd_set mask;
                    161: 
                    162:        mask = in | out | ex;
                    163:        for (i = 0 ; i < NR_OPEN ; i++,mask >>= 1) {
                    164:                if (!(mask & 1))
                    165:                        continue;
                    166:                if (!current->filp[i])
                    167:                        return -EBADF;
                    168:                if (!current->filp[i]->f_inode)
                    169:                        return -EBADF;
                    170:                if (current->filp[i]->f_inode->i_pipe)
                    171:                        continue;
                    172:                if (S_ISCHR(current->filp[i]->f_inode->i_mode))
                    173:                        continue;
                    174:                if (S_ISFIFO(current->filp[i]->f_inode->i_mode))
                    175:                        continue;
                    176:                return -EBADF;
                    177:        }
                    178: repeat:
                    179:        wait_table.nr = 0;
                    180:        *inp = *outp = *exp = 0;
                    181:        count = 0;
                    182:        mask = 1;
                    183:        for (i = 0 ; i < NR_OPEN ; i++, mask += mask) {
                    184:                if (mask & in)
                    185:                        if (check_in(&wait_table,current->filp[i]->f_inode)) {
                    186:                                *inp |= mask;
                    187:                                count++;
                    188:                        }
                    189:                if (mask & out)
                    190:                        if (check_out(&wait_table,current->filp[i]->f_inode)) {
                    191:                                *outp |= mask;
                    192:                                count++;
                    193:                        }
                    194:                if (mask & ex)
                    195:                        if (check_ex(&wait_table,current->filp[i]->f_inode)) {
                    196:                                *exp |= mask;
                    197:                                count++;
                    198:                        }
                    199:        }
                    200:        if (!(current->signal & ~current->blocked) &&
1.1.1.2 ! root      201:            current->timeout && !count) {
1.1       root      202:                current->state = TASK_INTERRUPTIBLE;
                    203:                schedule();
                    204:                free_wait(&wait_table);
                    205:                goto repeat;
                    206:        }
                    207:        free_wait(&wait_table);
                    208:        return count;
                    209: }
                    210: 
                    211: /*
                    212:  * Note that we cannot return -ERESTARTSYS, as we change our input
                    213:  * parameters. Sad, but there you are. We could do some tweaking in
                    214:  * the library function ...
                    215:  */
                    216: int sys_select( unsigned long *buffer )
                    217: {
                    218: /* Perform the select(nd, in, out, ex, tv) system call. */
                    219:        int i;
                    220:        fd_set res_in, in = 0, *inp;
                    221:        fd_set res_out, out = 0, *outp;
                    222:        fd_set res_ex, ex = 0, *exp;
                    223:        fd_set mask;
                    224:        struct timeval *tvp;
                    225:        unsigned long timeout;
                    226: 
1.1.1.2 ! root      227:        mask = get_fs_long(buffer++);
        !           228:        if (mask >= 32)
        !           229:                mask = ~0;
        !           230:        else
        !           231:                mask = ~((~0) << mask);
1.1       root      232:        inp = (fd_set *) get_fs_long(buffer++);
                    233:        outp = (fd_set *) get_fs_long(buffer++);
                    234:        exp = (fd_set *) get_fs_long(buffer++);
                    235:        tvp = (struct timeval *) get_fs_long(buffer);
                    236: 
                    237:        if (inp)
                    238:                in = mask & get_fs_long(inp);
                    239:        if (outp)
                    240:                out = mask & get_fs_long(outp);
                    241:        if (exp)
                    242:                ex = mask & get_fs_long(exp);
                    243:        timeout = 0xffffffff;
                    244:        if (tvp) {
                    245:                timeout = get_fs_long((unsigned long *)&tvp->tv_usec)/(1000000/HZ);
                    246:                timeout += get_fs_long((unsigned long *)&tvp->tv_sec) * HZ;
                    247:                timeout += jiffies;
                    248:        }
                    249:        current->timeout = timeout;
                    250:        cli();
                    251:        i = do_select(in, out, ex, &res_in, &res_out, &res_ex);
                    252:        if (current->timeout > jiffies)
                    253:                timeout = current->timeout - jiffies;
                    254:        else
                    255:                timeout = 0;
                    256:        sti();
                    257:        current->timeout = 0;
                    258:        if (i < 0)
                    259:                return i;
                    260:        if (inp) {
                    261:                verify_area(inp, 4);
                    262:                put_fs_long(res_in,inp);
                    263:        }
                    264:        if (outp) {
                    265:                verify_area(outp,4);
                    266:                put_fs_long(res_out,outp);
                    267:        }
                    268:        if (exp) {
                    269:                verify_area(exp,4);
                    270:                put_fs_long(res_ex,exp);
                    271:        }
                    272:        if (tvp) {
                    273:                verify_area(tvp, sizeof(*tvp));
                    274:                put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec);
                    275:                timeout %= HZ;
                    276:                timeout *= (1000000/HZ);
                    277:                put_fs_long(timeout, (unsigned long *) &tvp->tv_usec);
                    278:        }
                    279:        if (!i && (current->signal & ~current->blocked))
                    280:                return -EINTR;
                    281:        return i;
                    282: }

unix.superglobalmegacorp.com

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