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

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

unix.superglobalmegacorp.com

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