[BACK]Return to kern_event.c CVS log [TXT][DIR] Up to [local] / sys / kern

Annotation of sys/kern/kern_event.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: kern_event.c,v 1.31 2007/05/30 02:24:59 tedu Exp $    */
        !             2:
        !             3: /*-
        !             4:  * Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org>
        !             5:  * All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  *
        !            16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            17:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            18:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            19:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
        !            20:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            21:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            22:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            24:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            25:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            26:  * SUCH DAMAGE.
        !            27:  *
        !            28:  * $FreeBSD: src/sys/kern/kern_event.c,v 1.22 2001/02/23 20:32:42 jlemon Exp $
        !            29:  */
        !            30:
        !            31: #include <sys/param.h>
        !            32: #include <sys/systm.h>
        !            33: #include <sys/kernel.h>
        !            34: #include <sys/proc.h>
        !            35: #include <sys/malloc.h>
        !            36: #include <sys/unistd.h>
        !            37: #include <sys/file.h>
        !            38: #include <sys/filedesc.h>
        !            39: #include <sys/fcntl.h>
        !            40: #include <sys/selinfo.h>
        !            41: #include <sys/queue.h>
        !            42: #include <sys/event.h>
        !            43: #include <sys/eventvar.h>
        !            44: #include <sys/pool.h>
        !            45: #include <sys/protosw.h>
        !            46: #include <sys/socket.h>
        !            47: #include <sys/socketvar.h>
        !            48: #include <sys/stat.h>
        !            49: #include <sys/uio.h>
        !            50: #include <sys/mount.h>
        !            51: #include <sys/poll.h>
        !            52: #include <sys/syscallargs.h>
        !            53: #include <sys/timeout.h>
        !            54:
        !            55: int    kqueue_scan(struct file *fp, int maxevents,
        !            56:                    struct kevent *ulistp, const struct timespec *timeout,
        !            57:                    struct proc *p, int *retval);
        !            58:
        !            59: int    kqueue_read(struct file *fp, off_t *poff, struct uio *uio,
        !            60:                    struct ucred *cred);
        !            61: int    kqueue_write(struct file *fp, off_t *poff, struct uio *uio,
        !            62:                    struct ucred *cred);
        !            63: int    kqueue_ioctl(struct file *fp, u_long com, caddr_t data,
        !            64:                    struct proc *p);
        !            65: int    kqueue_poll(struct file *fp, int events, struct proc *p);
        !            66: int    kqueue_kqfilter(struct file *fp, struct knote *kn);
        !            67: int    kqueue_stat(struct file *fp, struct stat *st, struct proc *p);
        !            68: int    kqueue_close(struct file *fp, struct proc *p);
        !            69: void   kqueue_wakeup(struct kqueue *kq);
        !            70:
        !            71: struct fileops kqueueops = {
        !            72:        kqueue_read,
        !            73:        kqueue_write,
        !            74:        kqueue_ioctl,
        !            75:        kqueue_poll,
        !            76:        kqueue_kqfilter,
        !            77:        kqueue_stat,
        !            78:        kqueue_close
        !            79: };
        !            80:
        !            81: void   knote_attach(struct knote *kn, struct filedesc *fdp);
        !            82: void   knote_drop(struct knote *kn, struct proc *p, struct filedesc *fdp);
        !            83: void   knote_enqueue(struct knote *kn);
        !            84: void   knote_dequeue(struct knote *kn);
        !            85: #define knote_alloc() ((struct knote *)pool_get(&knote_pool, PR_WAITOK))
        !            86: #define knote_free(kn) pool_put(&knote_pool, (kn))
        !            87:
        !            88: void   filt_kqdetach(struct knote *kn);
        !            89: int    filt_kqueue(struct knote *kn, long hint);
        !            90: int    filt_procattach(struct knote *kn);
        !            91: void   filt_procdetach(struct knote *kn);
        !            92: int    filt_proc(struct knote *kn, long hint);
        !            93: int    filt_fileattach(struct knote *kn);
        !            94: void   filt_timerexpire(void *knx);
        !            95: int    filt_timerattach(struct knote *kn);
        !            96: void   filt_timerdetach(struct knote *kn);
        !            97: int    filt_timer(struct knote *kn, long hint);
        !            98:
        !            99: struct filterops kqread_filtops =
        !           100:        { 1, NULL, filt_kqdetach, filt_kqueue };
        !           101: struct filterops proc_filtops =
        !           102:        { 0, filt_procattach, filt_procdetach, filt_proc };
        !           103: struct filterops file_filtops =
        !           104:        { 1, filt_fileattach, NULL, NULL };
        !           105: struct filterops timer_filtops =
        !           106:         { 0, filt_timerattach, filt_timerdetach, filt_timer };
        !           107:
        !           108: struct pool knote_pool;
        !           109: struct pool kqueue_pool;
        !           110: int kq_ntimeouts = 0;
        !           111: int kq_timeoutmax = (4 * 1024);
        !           112:
        !           113: #define KNOTE_ACTIVATE(kn) do {                                                \
        !           114:        kn->kn_status |= KN_ACTIVE;                                     \
        !           115:        if ((kn->kn_status & (KN_QUEUED | KN_DISABLED)) == 0)           \
        !           116:                knote_enqueue(kn);                                      \
        !           117: } while(0)
        !           118:
        !           119: #define        KN_HASHSIZE             64              /* XXX should be tunable */
        !           120: #define KN_HASH(val, mask)     (((val) ^ (val >> 8)) & (mask))
        !           121:
        !           122: extern struct filterops sig_filtops;
        !           123: #ifdef notyet
        !           124: extern struct filterops aio_filtops;
        !           125: #endif
        !           126:
        !           127: /*
        !           128:  * Table for for all system-defined filters.
        !           129:  */
        !           130: struct filterops *sysfilt_ops[] = {
        !           131:        &file_filtops,                  /* EVFILT_READ */
        !           132:        &file_filtops,                  /* EVFILT_WRITE */
        !           133:        NULL, /*&aio_filtops,*/         /* EVFILT_AIO */
        !           134:        &file_filtops,                  /* EVFILT_VNODE */
        !           135:        &proc_filtops,                  /* EVFILT_PROC */
        !           136:        &sig_filtops,                   /* EVFILT_SIGNAL */
        !           137:        &timer_filtops,                 /* EVFILT_TIMER */
        !           138: };
        !           139:
        !           140: void kqueue_init(void);
        !           141:
        !           142: void
        !           143: kqueue_init(void)
        !           144: {
        !           145:
        !           146:        pool_init(&kqueue_pool, sizeof(struct kqueue), 0, 0, 0, "kqueuepl",
        !           147:            &pool_allocator_nointr);
        !           148:        pool_init(&knote_pool, sizeof(struct knote), 0, 0, 0, "knotepl",
        !           149:            &pool_allocator_nointr);
        !           150: }
        !           151:
        !           152: int
        !           153: filt_fileattach(struct knote *kn)
        !           154: {
        !           155:        struct file *fp = kn->kn_fp;
        !           156:
        !           157:        return ((*fp->f_ops->fo_kqfilter)(fp, kn));
        !           158: }
        !           159:
        !           160: int
        !           161: kqueue_kqfilter(struct file *fp, struct knote *kn)
        !           162: {
        !           163:        struct kqueue *kq = (struct kqueue *)kn->kn_fp->f_data;
        !           164:
        !           165:        if (kn->kn_filter != EVFILT_READ)
        !           166:                return (1);
        !           167:
        !           168:        kn->kn_fop = &kqread_filtops;
        !           169:        SLIST_INSERT_HEAD(&kq->kq_sel.si_note, kn, kn_selnext);
        !           170:        return (0);
        !           171: }
        !           172:
        !           173: void
        !           174: filt_kqdetach(struct knote *kn)
        !           175: {
        !           176:        struct kqueue *kq = (struct kqueue *)kn->kn_fp->f_data;
        !           177:
        !           178:        SLIST_REMOVE(&kq->kq_sel.si_note, kn, knote, kn_selnext);
        !           179: }
        !           180:
        !           181: /*ARGSUSED*/
        !           182: int
        !           183: filt_kqueue(struct knote *kn, long hint)
        !           184: {
        !           185:        struct kqueue *kq = (struct kqueue *)kn->kn_fp->f_data;
        !           186:
        !           187:        kn->kn_data = kq->kq_count;
        !           188:        return (kn->kn_data > 0);
        !           189: }
        !           190:
        !           191: int
        !           192: filt_procattach(struct knote *kn)
        !           193: {
        !           194:        struct proc *p;
        !           195:
        !           196:        p = pfind(kn->kn_id);
        !           197:        if (p == NULL)
        !           198:                return (ESRCH);
        !           199:
        !           200:        /*
        !           201:         * Fail if it's not owned by you, or the last exec gave us
        !           202:         * setuid/setgid privs (unless you're root).
        !           203:         */
        !           204:        if ((p->p_cred->p_ruid != curproc->p_cred->p_ruid ||
        !           205:            (p->p_flag & P_SUGID)) && suser(curproc, 0) != 0)
        !           206:                return (EACCES);
        !           207:
        !           208:        kn->kn_ptr.p_proc = p;
        !           209:        kn->kn_flags |= EV_CLEAR;               /* automatically set */
        !           210:
        !           211:        /*
        !           212:         * internal flag indicating registration done by kernel
        !           213:         */
        !           214:        if (kn->kn_flags & EV_FLAG1) {
        !           215:                kn->kn_data = kn->kn_sdata;             /* ppid */
        !           216:                kn->kn_fflags = NOTE_CHILD;
        !           217:                kn->kn_flags &= ~EV_FLAG1;
        !           218:        }
        !           219:
        !           220:        /* XXX lock the proc here while adding to the list? */
        !           221:        SLIST_INSERT_HEAD(&p->p_klist, kn, kn_selnext);
        !           222:
        !           223:        return (0);
        !           224: }
        !           225:
        !           226: /*
        !           227:  * The knote may be attached to a different process, which may exit,
        !           228:  * leaving nothing for the knote to be attached to.  So when the process
        !           229:  * exits, the knote is marked as DETACHED and also flagged as ONESHOT so
        !           230:  * it will be deleted when read out.  However, as part of the knote deletion,
        !           231:  * this routine is called, so a check is needed to avoid actually performing
        !           232:  * a detach, because the original process does not exist any more.
        !           233:  */
        !           234: void
        !           235: filt_procdetach(struct knote *kn)
        !           236: {
        !           237:        struct proc *p = kn->kn_ptr.p_proc;
        !           238:
        !           239:        if (kn->kn_status & KN_DETACHED)
        !           240:                return;
        !           241:
        !           242:        /* XXX locking?  this might modify another process. */
        !           243:        SLIST_REMOVE(&p->p_klist, kn, knote, kn_selnext);
        !           244: }
        !           245:
        !           246: int
        !           247: filt_proc(struct knote *kn, long hint)
        !           248: {
        !           249:        u_int event;
        !           250:
        !           251:        /*
        !           252:         * mask off extra data
        !           253:         */
        !           254:        event = (u_int)hint & NOTE_PCTRLMASK;
        !           255:
        !           256:        /*
        !           257:         * if the user is interested in this event, record it.
        !           258:         */
        !           259:        if (kn->kn_sfflags & event)
        !           260:                kn->kn_fflags |= event;
        !           261:
        !           262:        /*
        !           263:         * process is gone, so flag the event as finished.
        !           264:         */
        !           265:        if (event == NOTE_EXIT) {
        !           266:                kn->kn_status |= KN_DETACHED;
        !           267:                kn->kn_flags |= (EV_EOF | EV_ONESHOT);
        !           268:                return (1);
        !           269:        }
        !           270:
        !           271:        /*
        !           272:         * process forked, and user wants to track the new process,
        !           273:         * so attach a new knote to it, and immediately report an
        !           274:         * event with the parent's pid.
        !           275:         */
        !           276:        if ((event == NOTE_FORK) && (kn->kn_sfflags & NOTE_TRACK)) {
        !           277:                struct kevent kev;
        !           278:                int error;
        !           279:
        !           280:                /*
        !           281:                 * register knote with new process.
        !           282:                 */
        !           283:                kev.ident = hint & NOTE_PDATAMASK;      /* pid */
        !           284:                kev.filter = kn->kn_filter;
        !           285:                kev.flags = kn->kn_flags | EV_ADD | EV_ENABLE | EV_FLAG1;
        !           286:                kev.fflags = kn->kn_sfflags;
        !           287:                kev.data = kn->kn_id;                   /* parent */
        !           288:                kev.udata = kn->kn_kevent.udata;        /* preserve udata */
        !           289:                error = kqueue_register(kn->kn_kq, &kev, NULL);
        !           290:                if (error)
        !           291:                        kn->kn_fflags |= NOTE_TRACKERR;
        !           292:        }
        !           293:
        !           294:        return (kn->kn_fflags != 0);
        !           295: }
        !           296:
        !           297: void
        !           298: filt_timerexpire(void *knx)
        !           299: {
        !           300:        struct knote *kn = knx;
        !           301:        struct timeval tv;
        !           302:        int tticks;
        !           303:
        !           304:        kn->kn_data++;
        !           305:        KNOTE_ACTIVATE(kn);
        !           306:
        !           307:        if ((kn->kn_flags & EV_ONESHOT) == 0) {
        !           308:                tv.tv_sec = kn->kn_sdata / 1000;
        !           309:                tv.tv_usec = (kn->kn_sdata % 1000) * 1000;
        !           310:                tticks = tvtohz(&tv);
        !           311:                timeout_add((struct timeout *)kn->kn_hook, tticks);
        !           312:        }
        !           313: }
        !           314:
        !           315:
        !           316: /*
        !           317:  * data contains amount of time to sleep, in milliseconds
        !           318:  */
        !           319: int
        !           320: filt_timerattach(struct knote *kn)
        !           321: {
        !           322:        struct timeout *to;
        !           323:        struct timeval tv;
        !           324:        int tticks;
        !           325:
        !           326:        if (kq_ntimeouts > kq_timeoutmax)
        !           327:                return (ENOMEM);
        !           328:        kq_ntimeouts++;
        !           329:
        !           330:        tv.tv_sec = kn->kn_sdata / 1000;
        !           331:        tv.tv_usec = (kn->kn_sdata % 1000) * 1000;
        !           332:        tticks = tvtohz(&tv);
        !           333:
        !           334:        kn->kn_flags |= EV_CLEAR;       /* automatically set */
        !           335:        MALLOC(to, struct timeout *, sizeof(*to), M_KEVENT, 0);
        !           336:        timeout_set(to, filt_timerexpire, kn);
        !           337:        timeout_add(to, tticks);
        !           338:        kn->kn_hook = to;
        !           339:
        !           340:        return (0);
        !           341: }
        !           342:
        !           343: void
        !           344: filt_timerdetach(struct knote *kn)
        !           345: {
        !           346:        struct timeout *to;
        !           347:
        !           348:        to = (struct timeout *)kn->kn_hook;
        !           349:        timeout_del(to);
        !           350:        FREE(to, M_KEVENT);
        !           351:        kq_ntimeouts--;
        !           352: }
        !           353:
        !           354: int
        !           355: filt_timer(struct knote *kn, long hint)
        !           356: {
        !           357:        return (kn->kn_data != 0);
        !           358: }
        !           359:
        !           360:
        !           361: /*
        !           362:  * filt_seltrue:
        !           363:  *
        !           364:  *     This filter "event" routine simulates seltrue().
        !           365:  */
        !           366: int
        !           367: filt_seltrue(struct knote *kn, long hint)
        !           368: {
        !           369:
        !           370:        /*
        !           371:         * We don't know how much data can be read/written,
        !           372:         * but we know that it *can* be.  This is about as
        !           373:         * good as select/poll does as well.
        !           374:         */
        !           375:        kn->kn_data = 0;
        !           376:        return (1);
        !           377: }
        !           378:
        !           379: int
        !           380: sys_kqueue(struct proc *p, void *v, register_t *retval)
        !           381: {
        !           382:        struct filedesc *fdp = p->p_fd;
        !           383:        struct kqueue *kq;
        !           384:        struct file *fp;
        !           385:        int fd, error;
        !           386:
        !           387:        error = falloc(p, &fp, &fd);
        !           388:        if (error)
        !           389:                return (error);
        !           390:        fp->f_flag = FREAD | FWRITE;
        !           391:        fp->f_type = DTYPE_KQUEUE;
        !           392:        fp->f_ops = &kqueueops;
        !           393:        kq = pool_get(&kqueue_pool, PR_WAITOK);
        !           394:        bzero(kq, sizeof(*kq));
        !           395:        TAILQ_INIT(&kq->kq_head);
        !           396:        fp->f_data = (caddr_t)kq;
        !           397:        *retval = fd;
        !           398:        if (fdp->fd_knlistsize < 0)
        !           399:                fdp->fd_knlistsize = 0;         /* this process has a kq */
        !           400:        kq->kq_fdp = fdp;
        !           401:        FILE_SET_MATURE(fp);
        !           402:        return (0);
        !           403: }
        !           404:
        !           405: int
        !           406: sys_kevent(struct proc *p, void *v, register_t *retval)
        !           407: {
        !           408:        struct filedesc* fdp = p->p_fd;
        !           409:        struct sys_kevent_args /* {
        !           410:                syscallarg(int) fd;
        !           411:                syscallarg(const struct kevent *) changelist;
        !           412:                syscallarg(int) nchanges;
        !           413:                syscallarg(struct kevent *) eventlist;
        !           414:                syscallarg(int) nevents;
        !           415:                syscallarg(const struct timespec *) timeout;
        !           416:        } */ *uap = v;
        !           417:        struct kevent *kevp;
        !           418:        struct kqueue *kq;
        !           419:        struct file *fp;
        !           420:        struct timespec ts;
        !           421:        int i, n, nerrors, error;
        !           422:
        !           423:        if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL ||
        !           424:            (fp->f_type != DTYPE_KQUEUE))
        !           425:                return (EBADF);
        !           426:
        !           427:        FREF(fp);
        !           428:
        !           429:        if (SCARG(uap, timeout) != NULL) {
        !           430:                error = copyin(SCARG(uap, timeout), &ts, sizeof(ts));
        !           431:                if (error)
        !           432:                        goto done;
        !           433:                SCARG(uap, timeout) = &ts;
        !           434:        }
        !           435:
        !           436:        kq = (struct kqueue *)fp->f_data;
        !           437:        nerrors = 0;
        !           438:
        !           439:        while (SCARG(uap, nchanges) > 0) {
        !           440:                n = SCARG(uap, nchanges) > KQ_NEVENTS
        !           441:                        ? KQ_NEVENTS : SCARG(uap, nchanges);
        !           442:                error = copyin(SCARG(uap, changelist), kq->kq_kev,
        !           443:                    n * sizeof(struct kevent));
        !           444:                if (error)
        !           445:                        goto done;
        !           446:                for (i = 0; i < n; i++) {
        !           447:                        kevp = &kq->kq_kev[i];
        !           448:                        kevp->flags &= ~EV_SYSFLAGS;
        !           449:                        error = kqueue_register(kq, kevp, p);
        !           450:                        if (error) {
        !           451:                                if (SCARG(uap, nevents) != 0) {
        !           452:                                        kevp->flags = EV_ERROR;
        !           453:                                        kevp->data = error;
        !           454:                                        (void) copyout((caddr_t)kevp,
        !           455:                                            (caddr_t)SCARG(uap, eventlist),
        !           456:                                            sizeof(*kevp));
        !           457:                                        SCARG(uap, eventlist)++;
        !           458:                                        SCARG(uap, nevents)--;
        !           459:                                        nerrors++;
        !           460:                                } else {
        !           461:                                        goto done;
        !           462:                                }
        !           463:                        }
        !           464:                }
        !           465:                SCARG(uap, nchanges) -= n;
        !           466:                SCARG(uap, changelist) += n;
        !           467:        }
        !           468:        if (nerrors) {
        !           469:                *retval = nerrors;
        !           470:                error = 0;
        !           471:                goto done;
        !           472:        }
        !           473:
        !           474:        error = kqueue_scan(fp, SCARG(uap, nevents), SCARG(uap, eventlist),
        !           475:                            SCARG(uap, timeout), p, &n);
        !           476:        *retval = n;
        !           477:  done:
        !           478:        FRELE(fp);
        !           479:        return (error);
        !           480: }
        !           481:
        !           482: int
        !           483: kqueue_register(struct kqueue *kq, struct kevent *kev, struct proc *p)
        !           484: {
        !           485:        struct filedesc *fdp = kq->kq_fdp;
        !           486:        struct filterops *fops = NULL;
        !           487:        struct file *fp = NULL;
        !           488:        struct knote *kn = NULL;
        !           489:        int s, error = 0;
        !           490:
        !           491:        if (kev->filter < 0) {
        !           492:                if (kev->filter + EVFILT_SYSCOUNT < 0)
        !           493:                        return (EINVAL);
        !           494:                fops = sysfilt_ops[~kev->filter];       /* to 0-base index */
        !           495:        }
        !           496:
        !           497:        if (fops == NULL) {
        !           498:                /*
        !           499:                 * XXX
        !           500:                 * filter attach routine is responsible for ensuring that
        !           501:                 * the identifier can be attached to it.
        !           502:                 */
        !           503:                return (EINVAL);
        !           504:        }
        !           505:
        !           506:        if (fops->f_isfd) {
        !           507:                /* validate descriptor */
        !           508:                if ((fp = fd_getfile(fdp, kev->ident)) == NULL)
        !           509:                        return (EBADF);
        !           510:                FREF(fp);
        !           511:                fp->f_count++;
        !           512:
        !           513:                if (kev->ident < fdp->fd_knlistsize) {
        !           514:                        SLIST_FOREACH(kn, &fdp->fd_knlist[kev->ident], kn_link)
        !           515:                                if (kq == kn->kn_kq &&
        !           516:                                    kev->filter == kn->kn_filter)
        !           517:                                        break;
        !           518:                }
        !           519:        } else {
        !           520:                if (fdp->fd_knhashmask != 0) {
        !           521:                        struct klist *list;
        !           522:
        !           523:                        list = &fdp->fd_knhash[
        !           524:                            KN_HASH((u_long)kev->ident, fdp->fd_knhashmask)];
        !           525:                        SLIST_FOREACH(kn, list, kn_link)
        !           526:                                if (kev->ident == kn->kn_id &&
        !           527:                                    kq == kn->kn_kq &&
        !           528:                                    kev->filter == kn->kn_filter)
        !           529:                                        break;
        !           530:                }
        !           531:        }
        !           532:
        !           533:        if (kn == NULL && ((kev->flags & EV_ADD) == 0)) {
        !           534:                error = ENOENT;
        !           535:                goto done;
        !           536:        }
        !           537:
        !           538:        /*
        !           539:         * kn now contains the matching knote, or NULL if no match
        !           540:         */
        !           541:        if (kev->flags & EV_ADD) {
        !           542:
        !           543:                if (kn == NULL) {
        !           544:                        kn = knote_alloc();
        !           545:                        if (kn == NULL) {
        !           546:                                error = ENOMEM;
        !           547:                                goto done;
        !           548:                        }
        !           549:                        kn->kn_fp = fp;
        !           550:                        kn->kn_kq = kq;
        !           551:                        kn->kn_fop = fops;
        !           552:
        !           553:                        /*
        !           554:                         * apply reference count to knote structure, and
        !           555:                         * do not release it at the end of this routine.
        !           556:                         */
        !           557:                        if (fp != NULL)
        !           558:                                FRELE(fp);
        !           559:                        fp = NULL;
        !           560:
        !           561:                        kn->kn_sfflags = kev->fflags;
        !           562:                        kn->kn_sdata = kev->data;
        !           563:                        kev->fflags = 0;
        !           564:                        kev->data = 0;
        !           565:                        kn->kn_kevent = *kev;
        !           566:
        !           567:                        knote_attach(kn, fdp);
        !           568:                        if ((error = fops->f_attach(kn)) != 0) {
        !           569:                                knote_drop(kn, p, fdp);
        !           570:                                goto done;
        !           571:                        }
        !           572:                } else {
        !           573:                        /*
        !           574:                         * The user may change some filter values after the
        !           575:                         * initial EV_ADD, but doing so will not reset any
        !           576:                         * filters which have already been triggered.
        !           577:                         */
        !           578:                        kn->kn_sfflags = kev->fflags;
        !           579:                        kn->kn_sdata = kev->data;
        !           580:                        kn->kn_kevent.udata = kev->udata;
        !           581:                }
        !           582:
        !           583:                s = splhigh();
        !           584:                if (kn->kn_fop->f_event(kn, 0))
        !           585:                        KNOTE_ACTIVATE(kn);
        !           586:                splx(s);
        !           587:
        !           588:        } else if (kev->flags & EV_DELETE) {
        !           589:                kn->kn_fop->f_detach(kn);
        !           590:                knote_drop(kn, p, p->p_fd);
        !           591:                goto done;
        !           592:        }
        !           593:
        !           594:        if ((kev->flags & EV_DISABLE) &&
        !           595:            ((kn->kn_status & KN_DISABLED) == 0)) {
        !           596:                s = splhigh();
        !           597:                kn->kn_status |= KN_DISABLED;
        !           598:                splx(s);
        !           599:        }
        !           600:
        !           601:        if ((kev->flags & EV_ENABLE) && (kn->kn_status & KN_DISABLED)) {
        !           602:                s = splhigh();
        !           603:                kn->kn_status &= ~KN_DISABLED;
        !           604:                if ((kn->kn_status & KN_ACTIVE) &&
        !           605:                    ((kn->kn_status & KN_QUEUED) == 0))
        !           606:                        knote_enqueue(kn);
        !           607:                splx(s);
        !           608:        }
        !           609:
        !           610: done:
        !           611:        if (fp != NULL)
        !           612:                closef(fp, p);
        !           613:        return (error);
        !           614: }
        !           615:
        !           616: int
        !           617: kqueue_scan(struct file *fp, int maxevents, struct kevent *ulistp,
        !           618:        const struct timespec *tsp, struct proc *p, int *retval)
        !           619: {
        !           620:        struct kqueue *kq = (struct kqueue *)fp->f_data;
        !           621:        struct kevent *kevp;
        !           622:        struct timeval atv, rtv, ttv;
        !           623:        struct knote *kn, marker;
        !           624:        int s, count, timeout, nkev = 0, error = 0;
        !           625:
        !           626:        count = maxevents;
        !           627:        if (count == 0)
        !           628:                goto done;
        !           629:
        !           630:        if (tsp != NULL) {
        !           631:                TIMESPEC_TO_TIMEVAL(&atv, tsp);
        !           632:                if (tsp->tv_sec == 0 && tsp->tv_nsec == 0) {
        !           633:                        /* No timeout, just poll */
        !           634:                        timeout = -1;
        !           635:                        goto start;
        !           636:                }
        !           637:                if (itimerfix(&atv)) {
        !           638:                        error = EINVAL;
        !           639:                        goto done;
        !           640:                }
        !           641:
        !           642:                timeout = atv.tv_sec > 24 * 60 * 60 ?
        !           643:                        24 * 60 * 60 * hz : tvtohz(&atv);
        !           644:
        !           645:                getmicrouptime(&rtv);
        !           646:                timeradd(&atv, &rtv, &atv);
        !           647:        } else {
        !           648:                atv.tv_sec = 0;
        !           649:                atv.tv_usec = 0;
        !           650:                timeout = 0;
        !           651:        }
        !           652:        goto start;
        !           653:
        !           654: retry:
        !           655:        if (atv.tv_sec || atv.tv_usec) {
        !           656:                getmicrouptime(&rtv);
        !           657:                if (timercmp(&rtv, &atv, >=))
        !           658:                        goto done;
        !           659:                ttv = atv;
        !           660:                timersub(&ttv, &rtv, &ttv);
        !           661:                timeout = ttv.tv_sec > 24 * 60 * 60 ?
        !           662:                        24 * 60 * 60 * hz : tvtohz(&ttv);
        !           663:        }
        !           664:
        !           665: start:
        !           666:        kevp = kq->kq_kev;
        !           667:        s = splhigh();
        !           668:        if (kq->kq_count == 0) {
        !           669:                if (timeout < 0) {
        !           670:                        error = EWOULDBLOCK;
        !           671:                } else {
        !           672:                        kq->kq_state |= KQ_SLEEP;
        !           673:                        error = tsleep(kq, PSOCK | PCATCH, "kqread", timeout);
        !           674:                }
        !           675:                splx(s);
        !           676:                if (error == 0)
        !           677:                        goto retry;
        !           678:                /* don't restart after signals... */
        !           679:                if (error == ERESTART)
        !           680:                        error = EINTR;
        !           681:                else if (error == EWOULDBLOCK)
        !           682:                        error = 0;
        !           683:                goto done;
        !           684:        }
        !           685:
        !           686:        TAILQ_INSERT_TAIL(&kq->kq_head, &marker, kn_tqe);
        !           687:        while (count) {
        !           688:                kn = TAILQ_FIRST(&kq->kq_head);
        !           689:                TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe);
        !           690:                if (kn == &marker) {
        !           691:                        splx(s);
        !           692:                        if (count == maxevents)
        !           693:                                goto retry;
        !           694:                        goto done;
        !           695:                }
        !           696:                if (kn->kn_status & KN_DISABLED) {
        !           697:                        kn->kn_status &= ~KN_QUEUED;
        !           698:                        kq->kq_count--;
        !           699:                        continue;
        !           700:                }
        !           701:                if ((kn->kn_flags & EV_ONESHOT) == 0 &&
        !           702:                    kn->kn_fop->f_event(kn, 0) == 0) {
        !           703:                        kn->kn_status &= ~(KN_QUEUED | KN_ACTIVE);
        !           704:                        kq->kq_count--;
        !           705:                        continue;
        !           706:                }
        !           707:                *kevp = kn->kn_kevent;
        !           708:                kevp++;
        !           709:                nkev++;
        !           710:                if (kn->kn_flags & EV_ONESHOT) {
        !           711:                        kn->kn_status &= ~KN_QUEUED;
        !           712:                        kq->kq_count--;
        !           713:                        splx(s);
        !           714:                        kn->kn_fop->f_detach(kn);
        !           715:                        knote_drop(kn, p, p->p_fd);
        !           716:                        s = splhigh();
        !           717:                } else if (kn->kn_flags & EV_CLEAR) {
        !           718:                        kn->kn_data = 0;
        !           719:                        kn->kn_fflags = 0;
        !           720:                        kn->kn_status &= ~(KN_QUEUED | KN_ACTIVE);
        !           721:                        kq->kq_count--;
        !           722:                } else {
        !           723:                        TAILQ_INSERT_TAIL(&kq->kq_head, kn, kn_tqe);
        !           724:                }
        !           725:                count--;
        !           726:                if (nkev == KQ_NEVENTS) {
        !           727:                        splx(s);
        !           728:                        error = copyout((caddr_t)&kq->kq_kev, (caddr_t)ulistp,
        !           729:                            sizeof(struct kevent) * nkev);
        !           730:                        ulistp += nkev;
        !           731:                        nkev = 0;
        !           732:                        kevp = kq->kq_kev;
        !           733:                        s = splhigh();
        !           734:                        if (error)
        !           735:                                break;
        !           736:                }
        !           737:        }
        !           738:        TAILQ_REMOVE(&kq->kq_head, &marker, kn_tqe);
        !           739:        splx(s);
        !           740: done:
        !           741:        if (nkev != 0)
        !           742:                error = copyout((caddr_t)&kq->kq_kev, (caddr_t)ulistp,
        !           743:                    sizeof(struct kevent) * nkev);
        !           744:        *retval = maxevents - count;
        !           745:        return (error);
        !           746: }
        !           747:
        !           748: /*
        !           749:  * XXX
        !           750:  * This could be expanded to call kqueue_scan, if desired.
        !           751:  */
        !           752: /*ARGSUSED*/
        !           753: int
        !           754: kqueue_read(struct file *fp, off_t *poff, struct uio *uio, struct ucred *cred)
        !           755: {
        !           756:        return (ENXIO);
        !           757: }
        !           758:
        !           759: /*ARGSUSED*/
        !           760: int
        !           761: kqueue_write(struct file *fp, off_t *poff, struct uio *uio, struct ucred *cred)
        !           762:
        !           763: {
        !           764:        return (ENXIO);
        !           765: }
        !           766:
        !           767: /*ARGSUSED*/
        !           768: int
        !           769: kqueue_ioctl(struct file *fp, u_long com, caddr_t data, struct proc *p)
        !           770: {
        !           771:        return (ENOTTY);
        !           772: }
        !           773:
        !           774: /*ARGSUSED*/
        !           775: int
        !           776: kqueue_poll(struct file *fp, int events, struct proc *p)
        !           777: {
        !           778:        struct kqueue *kq = (struct kqueue *)fp->f_data;
        !           779:        int revents = 0;
        !           780:        int s = splhigh();
        !           781:
        !           782:        if (events & (POLLIN | POLLRDNORM)) {
        !           783:                if (kq->kq_count) {
        !           784:                        revents |= events & (POLLIN | POLLRDNORM);
        !           785:                } else {
        !           786:                        selrecord(p, &kq->kq_sel);
        !           787:                        kq->kq_state |= KQ_SEL;
        !           788:                }
        !           789:        }
        !           790:        splx(s);
        !           791:        return (revents);
        !           792: }
        !           793:
        !           794: /*ARGSUSED*/
        !           795: int
        !           796: kqueue_stat(struct file *fp, struct stat *st, struct proc *p)
        !           797: {
        !           798:        struct kqueue *kq = (struct kqueue *)fp->f_data;
        !           799:
        !           800:        bzero((void *)st, sizeof(*st));
        !           801:        st->st_size = kq->kq_count;
        !           802:        st->st_blksize = sizeof(struct kevent);
        !           803:        st->st_mode = S_IFIFO;
        !           804:        return (0);
        !           805: }
        !           806:
        !           807: /*ARGSUSED*/
        !           808: int
        !           809: kqueue_close(struct file *fp, struct proc *p)
        !           810: {
        !           811:        struct kqueue *kq = (struct kqueue *)fp->f_data;
        !           812:        struct filedesc *fdp = p->p_fd;
        !           813:        struct knote **knp, *kn, *kn0;
        !           814:        int i;
        !           815:
        !           816:        for (i = 0; i < fdp->fd_knlistsize; i++) {
        !           817:                knp = &SLIST_FIRST(&fdp->fd_knlist[i]);
        !           818:                kn = *knp;
        !           819:                while (kn != NULL) {
        !           820:                        kn0 = SLIST_NEXT(kn, kn_link);
        !           821:                        if (kq == kn->kn_kq) {
        !           822:                                FREF(kn->kn_fp);
        !           823:                                kn->kn_fop->f_detach(kn);
        !           824:                                closef(kn->kn_fp, p);
        !           825:                                knote_free(kn);
        !           826:                                *knp = kn0;
        !           827:                        } else {
        !           828:                                knp = &SLIST_NEXT(kn, kn_link);
        !           829:                        }
        !           830:                        kn = kn0;
        !           831:                }
        !           832:        }
        !           833:        if (fdp->fd_knhashmask != 0) {
        !           834:                for (i = 0; i < fdp->fd_knhashmask + 1; i++) {
        !           835:                        knp = &SLIST_FIRST(&fdp->fd_knhash[i]);
        !           836:                        kn = *knp;
        !           837:                        while (kn != NULL) {
        !           838:                                kn0 = SLIST_NEXT(kn, kn_link);
        !           839:                                if (kq == kn->kn_kq) {
        !           840:                                        kn->kn_fop->f_detach(kn);
        !           841:                /* XXX non-fd release of kn->kn_ptr */
        !           842:                                        knote_free(kn);
        !           843:                                        *knp = kn0;
        !           844:                                } else {
        !           845:                                        knp = &SLIST_NEXT(kn, kn_link);
        !           846:                                }
        !           847:                                kn = kn0;
        !           848:                        }
        !           849:                }
        !           850:        }
        !           851:        pool_put(&kqueue_pool, kq);
        !           852:        fp->f_data = NULL;
        !           853:
        !           854:        return (0);
        !           855: }
        !           856:
        !           857: void
        !           858: kqueue_wakeup(struct kqueue *kq)
        !           859: {
        !           860:
        !           861:        if (kq->kq_state & KQ_SLEEP) {
        !           862:                kq->kq_state &= ~KQ_SLEEP;
        !           863:                wakeup(kq);
        !           864:        }
        !           865:        if (kq->kq_state & KQ_SEL) {
        !           866:                kq->kq_state &= ~KQ_SEL;
        !           867:                selwakeup(&kq->kq_sel);
        !           868:        }
        !           869:        KNOTE(&kq->kq_sel.si_note, 0);
        !           870: }
        !           871:
        !           872: /*
        !           873:  * walk down a list of knotes, activating them if their event has triggered.
        !           874:  */
        !           875: void
        !           876: knote(struct klist *list, long hint)
        !           877: {
        !           878:        struct knote *kn;
        !           879:
        !           880:        SLIST_FOREACH(kn, list, kn_selnext)
        !           881:                if (kn->kn_fop->f_event(kn, hint))
        !           882:                        KNOTE_ACTIVATE(kn);
        !           883: }
        !           884:
        !           885: /*
        !           886:  * remove all knotes from a specified klist
        !           887:  */
        !           888: void
        !           889: knote_remove(struct proc *p, struct klist *list)
        !           890: {
        !           891:        struct knote *kn;
        !           892:
        !           893:        while ((kn = SLIST_FIRST(list)) != NULL) {
        !           894:                kn->kn_fop->f_detach(kn);
        !           895:                knote_drop(kn, p, p->p_fd);
        !           896:        }
        !           897: }
        !           898:
        !           899: /*
        !           900:  * remove all knotes referencing a specified fd
        !           901:  */
        !           902: void
        !           903: knote_fdclose(struct proc *p, int fd)
        !           904: {
        !           905:        struct filedesc *fdp = p->p_fd;
        !           906:        struct klist *list = &fdp->fd_knlist[fd];
        !           907:
        !           908:        knote_remove(p, list);
        !           909: }
        !           910:
        !           911: void
        !           912: knote_attach(struct knote *kn, struct filedesc *fdp)
        !           913: {
        !           914:        struct klist *list;
        !           915:        int size;
        !           916:
        !           917:        if (! kn->kn_fop->f_isfd) {
        !           918:                if (fdp->fd_knhashmask == 0)
        !           919:                        fdp->fd_knhash = hashinit(KN_HASHSIZE, M_TEMP,
        !           920:                            M_WAITOK, &fdp->fd_knhashmask);
        !           921:                list = &fdp->fd_knhash[KN_HASH(kn->kn_id, fdp->fd_knhashmask)];
        !           922:                goto done;
        !           923:        }
        !           924:
        !           925:        if (fdp->fd_knlistsize <= kn->kn_id) {
        !           926:                size = fdp->fd_knlistsize;
        !           927:                while (size <= kn->kn_id)
        !           928:                        size += KQEXTENT;
        !           929:                list = malloc(size * sizeof(struct klist *), M_TEMP, M_WAITOK);
        !           930:                bcopy((caddr_t)fdp->fd_knlist, (caddr_t)list,
        !           931:                    fdp->fd_knlistsize * sizeof(struct klist *));
        !           932:                bzero((caddr_t)list +
        !           933:                    fdp->fd_knlistsize * sizeof(struct klist *),
        !           934:                    (size - fdp->fd_knlistsize) * sizeof(struct klist *));
        !           935:                if (fdp->fd_knlist != NULL)
        !           936:                        free(fdp->fd_knlist, M_TEMP);
        !           937:                fdp->fd_knlistsize = size;
        !           938:                fdp->fd_knlist = list;
        !           939:        }
        !           940:        list = &fdp->fd_knlist[kn->kn_id];
        !           941: done:
        !           942:        SLIST_INSERT_HEAD(list, kn, kn_link);
        !           943:        kn->kn_status = 0;
        !           944: }
        !           945:
        !           946: /*
        !           947:  * should be called at spl == 0, since we don't want to hold spl
        !           948:  * while calling closef and free.
        !           949:  */
        !           950: void
        !           951: knote_drop(struct knote *kn, struct proc *p, struct filedesc *fdp)
        !           952: {
        !           953:        struct klist *list;
        !           954:
        !           955:        if (kn->kn_fop->f_isfd)
        !           956:                list = &fdp->fd_knlist[kn->kn_id];
        !           957:        else
        !           958:                list = &fdp->fd_knhash[KN_HASH(kn->kn_id, fdp->fd_knhashmask)];
        !           959:
        !           960:        SLIST_REMOVE(list, kn, knote, kn_link);
        !           961:        if (kn->kn_status & KN_QUEUED)
        !           962:                knote_dequeue(kn);
        !           963:        if (kn->kn_fop->f_isfd) {
        !           964:                FREF(kn->kn_fp);
        !           965:                closef(kn->kn_fp, p);
        !           966:        }
        !           967:        knote_free(kn);
        !           968: }
        !           969:
        !           970:
        !           971: void
        !           972: knote_enqueue(struct knote *kn)
        !           973: {
        !           974:        struct kqueue *kq = kn->kn_kq;
        !           975:        int s = splhigh();
        !           976:
        !           977:        KASSERT((kn->kn_status & KN_QUEUED) == 0);
        !           978:
        !           979:        TAILQ_INSERT_TAIL(&kq->kq_head, kn, kn_tqe);
        !           980:        kn->kn_status |= KN_QUEUED;
        !           981:        kq->kq_count++;
        !           982:        splx(s);
        !           983:        kqueue_wakeup(kq);
        !           984: }
        !           985:
        !           986: void
        !           987: knote_dequeue(struct knote *kn)
        !           988: {
        !           989:        struct kqueue *kq = kn->kn_kq;
        !           990:        int s = splhigh();
        !           991:
        !           992:        KASSERT(kn->kn_status & KN_QUEUED);
        !           993:
        !           994:        TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe);
        !           995:        kn->kn_status &= ~KN_QUEUED;
        !           996:        kq->kq_count--;
        !           997:        splx(s);
        !           998: }
        !           999:
        !          1000: void
        !          1001: klist_invalidate(struct klist *list)
        !          1002: {
        !          1003:        struct knote *kn;
        !          1004:
        !          1005:        SLIST_FOREACH(kn, list, kn_selnext) {
        !          1006:                kn->kn_status |= KN_DETACHED;
        !          1007:                kn->kn_flags |= EV_EOF | EV_ONESHOT;
        !          1008:        }
        !          1009: }

CVSweb