Annotation of embedaddon/libevent/kqueue.c, revision 1.1.1.1

1.1       misho       1: /*     $OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $  */
                      2: 
                      3: /*
                      4:  * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
                      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:  * 3. The name of the author may not be used to endorse or promote products
                     16:  *    derived from this software without specific prior written permission.
                     17:  *
                     18:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     19:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     20:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     21:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     22:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     23:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     24:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     25:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     26:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     27:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     28:  */
                     29: #ifdef HAVE_CONFIG_H
                     30: #include "config.h"
                     31: #endif
                     32: 
                     33: #define _GNU_SOURCE 1
                     34: 
                     35: #include <sys/types.h>
                     36: #ifdef HAVE_SYS_TIME_H
                     37: #include <sys/time.h>
                     38: #else
                     39: #include <sys/_libevent_time.h>
                     40: #endif
                     41: #include <sys/queue.h>
                     42: #include <sys/event.h>
                     43: #include <signal.h>
                     44: #include <stdio.h>
                     45: #include <stdlib.h>
                     46: #include <string.h>
                     47: #include <unistd.h>
                     48: #include <errno.h>
                     49: #include <assert.h>
                     50: #ifdef HAVE_INTTYPES_H
                     51: #include <inttypes.h>
                     52: #endif
                     53: 
                     54: /* Some platforms apparently define the udata field of struct kevent as
                     55:  * intptr_t, whereas others define it as void*.  There doesn't seem to be an
                     56:  * easy way to tell them apart via autoconf, so we need to use OS macros. */
                     57: #if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__)
                     58: #define PTR_TO_UDATA(x)        ((intptr_t)(x))
                     59: #else
                     60: #define PTR_TO_UDATA(x)        (x)
                     61: #endif
                     62: 
                     63: #include "event.h"
                     64: #include "event-internal.h"
                     65: #include "log.h"
                     66: #include "evsignal.h"
                     67: 
                     68: #define EVLIST_X_KQINKERNEL    0x1000
                     69: 
                     70: #define NEVENT         64
                     71: 
                     72: struct kqop {
                     73:        struct kevent *changes;
                     74:        int nchanges;
                     75:        struct kevent *events;
                     76:        struct event_list evsigevents[NSIG];
                     77:        int nevents;
                     78:        int kq;
                     79:        pid_t pid;
                     80: };
                     81: 
                     82: static void *kq_init   (struct event_base *);
                     83: static int kq_add      (void *, struct event *);
                     84: static int kq_del      (void *, struct event *);
                     85: static int kq_dispatch (struct event_base *, void *, struct timeval *);
                     86: static int kq_insert   (struct kqop *, struct kevent *);
                     87: static void kq_dealloc (struct event_base *, void *);
                     88: 
                     89: const struct eventop kqops = {
                     90:        "kqueue",
                     91:        kq_init,
                     92:        kq_add,
                     93:        kq_del,
                     94:        kq_dispatch,
                     95:        kq_dealloc,
                     96:        1 /* need reinit */
                     97: };
                     98: 
                     99: static void *
                    100: kq_init(struct event_base *base)
                    101: {
                    102:        int i, kq;
                    103:        struct kqop *kqueueop;
                    104: 
                    105:        /* Disable kqueue when this environment variable is set */
                    106:        if (evutil_getenv("EVENT_NOKQUEUE"))
                    107:                return (NULL);
                    108: 
                    109:        if (!(kqueueop = calloc(1, sizeof(struct kqop))))
                    110:                return (NULL);
                    111: 
                    112:        /* Initalize the kernel queue */
                    113:        
                    114:        if ((kq = kqueue()) == -1) {
                    115:                event_warn("kqueue");
                    116:                free (kqueueop);
                    117:                return (NULL);
                    118:        }
                    119: 
                    120:        kqueueop->kq = kq;
                    121: 
                    122:        kqueueop->pid = getpid();
                    123: 
                    124:        /* Initalize fields */
                    125:        kqueueop->changes = malloc(NEVENT * sizeof(struct kevent));
                    126:        if (kqueueop->changes == NULL) {
                    127:                free (kqueueop);
                    128:                return (NULL);
                    129:        }
                    130:        kqueueop->events = malloc(NEVENT * sizeof(struct kevent));
                    131:        if (kqueueop->events == NULL) {
                    132:                free (kqueueop->changes);
                    133:                free (kqueueop);
                    134:                return (NULL);
                    135:        }
                    136:        kqueueop->nevents = NEVENT;
                    137: 
                    138:        /* we need to keep track of multiple events per signal */
                    139:        for (i = 0; i < NSIG; ++i) {
                    140:                TAILQ_INIT(&kqueueop->evsigevents[i]);
                    141:        }
                    142: 
                    143:        /* Check for Mac OS X kqueue bug. */
                    144:        memset(&kqueueop->changes[0], 0, sizeof kqueueop->changes[0]);
                    145:        kqueueop->changes[0].ident = -1;
                    146:        kqueueop->changes[0].filter = EVFILT_READ;
                    147:        kqueueop->changes[0].flags = EV_ADD;
                    148:        /* 
                    149:         * If kqueue works, then kevent will succeed, and it will
                    150:         * stick an error in events[0].  If kqueue is broken, then
                    151:         * kevent will fail.
                    152:         */
                    153:        if (kevent(kq,
                    154:                kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 ||
                    155:            kqueueop->events[0].ident != -1 ||
                    156:            kqueueop->events[0].flags != EV_ERROR) {
                    157:                event_warn("%s: detected broken kqueue; not using.", __func__);
                    158:                free(kqueueop->changes);
                    159:                free(kqueueop->events);
                    160:                free(kqueueop);
                    161:                close(kq);
                    162:                return (NULL);
                    163:        }
                    164: 
                    165:        return (kqueueop);
                    166: }
                    167: 
                    168: static int
                    169: kq_insert(struct kqop *kqop, struct kevent *kev)
                    170: {
                    171:        int nevents = kqop->nevents;
                    172: 
                    173:        if (kqop->nchanges == nevents) {
                    174:                struct kevent *newchange;
                    175:                struct kevent *newresult;
                    176: 
                    177:                nevents *= 2;
                    178: 
                    179:                newchange = realloc(kqop->changes,
                    180:                                    nevents * sizeof(struct kevent));
                    181:                if (newchange == NULL) {
                    182:                        event_warn("%s: malloc", __func__);
                    183:                        return (-1);
                    184:                }
                    185:                kqop->changes = newchange;
                    186: 
                    187:                newresult = realloc(kqop->events,
                    188:                                    nevents * sizeof(struct kevent));
                    189: 
                    190:                /*
                    191:                 * If we fail, we don't have to worry about freeing,
                    192:                 * the next realloc will pick it up.
                    193:                 */
                    194:                if (newresult == NULL) {
                    195:                        event_warn("%s: malloc", __func__);
                    196:                        return (-1);
                    197:                }
                    198:                kqop->events = newresult;
                    199: 
                    200:                kqop->nevents = nevents;
                    201:        }
                    202: 
                    203:        memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
                    204: 
                    205:        event_debug(("%s: fd %d %s%s",
                    206:                __func__, (int)kev->ident, 
                    207:                kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
                    208:                kev->flags == EV_DELETE ? " (del)" : ""));
                    209: 
                    210:        return (0);
                    211: }
                    212: 
                    213: static void
                    214: kq_sighandler(int sig)
                    215: {
                    216:        /* Do nothing here */
                    217: }
                    218: 
                    219: static int
                    220: kq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
                    221: {
                    222:        struct kqop *kqop = arg;
                    223:        struct kevent *changes = kqop->changes;
                    224:        struct kevent *events = kqop->events;
                    225:        struct event *ev;
                    226:        struct timespec ts, *ts_p = NULL;
                    227:        int i, res;
                    228: 
                    229:        if (tv != NULL) {
                    230:                TIMEVAL_TO_TIMESPEC(tv, &ts);
                    231:                ts_p = &ts;
                    232:        }
                    233: 
                    234:        res = kevent(kqop->kq, changes, kqop->nchanges,
                    235:            events, kqop->nevents, ts_p);
                    236:        kqop->nchanges = 0;
                    237:        if (res == -1) {
                    238:                if (errno != EINTR) {
                    239:                         event_warn("kevent");
                    240:                        return (-1);
                    241:                }
                    242: 
                    243:                return (0);
                    244:        }
                    245: 
                    246:        event_debug(("%s: kevent reports %d", __func__, res));
                    247: 
                    248:        for (i = 0; i < res; i++) {
                    249:                int which = 0;
                    250: 
                    251:                if (events[i].flags & EV_ERROR) {
                    252:                        /* 
                    253:                         * Error messages that can happen, when a delete fails.
                    254:                         *   EBADF happens when the file discriptor has been
                    255:                         *   closed,
                    256:                         *   ENOENT when the file discriptor was closed and
                    257:                         *   then reopened.
                    258:                         *   EINVAL for some reasons not understood; EINVAL
                    259:                         *   should not be returned ever; but FreeBSD does :-\
                    260:                         * An error is also indicated when a callback deletes
                    261:                         * an event we are still processing.  In that case
                    262:                         * the data field is set to ENOENT.
                    263:                         */
                    264:                        if (events[i].data == EBADF ||
                    265:                            events[i].data == EINVAL ||
                    266:                            events[i].data == ENOENT)
                    267:                                continue;
                    268:                        errno = events[i].data;
                    269:                        return (-1);
                    270:                }
                    271: 
                    272:                if (events[i].filter == EVFILT_READ) {
                    273:                        which |= EV_READ;
                    274:                } else if (events[i].filter == EVFILT_WRITE) {
                    275:                        which |= EV_WRITE;
                    276:                } else if (events[i].filter == EVFILT_SIGNAL) {
                    277:                        which |= EV_SIGNAL;
                    278:                }
                    279: 
                    280:                if (!which)
                    281:                        continue;
                    282: 
                    283:                if (events[i].filter == EVFILT_SIGNAL) {
                    284:                        struct event_list *head =
                    285:                            (struct event_list *)events[i].udata;
                    286:                        TAILQ_FOREACH(ev, head, ev_signal_next) {
                    287:                                event_active(ev, which, events[i].data);
                    288:                        }
                    289:                } else {
                    290:                        ev = (struct event *)events[i].udata;
                    291: 
                    292:                        if (!(ev->ev_events & EV_PERSIST))
                    293:                                ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
                    294: 
                    295:                        event_active(ev, which, 1);
                    296:                }
                    297:        }
                    298: 
                    299:        return (0);
                    300: }
                    301: 
                    302: 
                    303: static int
                    304: kq_add(void *arg, struct event *ev)
                    305: {
                    306:        struct kqop *kqop = arg;
                    307:        struct kevent kev;
                    308: 
                    309:        if (ev->ev_events & EV_SIGNAL) {
                    310:                int nsignal = EVENT_SIGNAL(ev);
                    311: 
                    312:                assert(nsignal >= 0 && nsignal < NSIG);
                    313:                if (TAILQ_EMPTY(&kqop->evsigevents[nsignal])) {
                    314:                        struct timespec timeout = { 0, 0 };
                    315:                        
                    316:                        memset(&kev, 0, sizeof(kev));
                    317:                        kev.ident = nsignal;
                    318:                        kev.filter = EVFILT_SIGNAL;
                    319:                        kev.flags = EV_ADD;
                    320:                        kev.udata = PTR_TO_UDATA(&kqop->evsigevents[nsignal]);
                    321:                        
                    322:                        /* Be ready for the signal if it is sent any
                    323:                         * time between now and the next call to
                    324:                         * kq_dispatch. */
                    325:                        if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
                    326:                                return (-1);
                    327:                        
                    328:                        if (_evsignal_set_handler(ev->ev_base, nsignal,
                    329:                                kq_sighandler) == -1)
                    330:                                return (-1);
                    331:                }
                    332: 
                    333:                TAILQ_INSERT_TAIL(&kqop->evsigevents[nsignal], ev,
                    334:                    ev_signal_next);
                    335:                ev->ev_flags |= EVLIST_X_KQINKERNEL;
                    336:                return (0);
                    337:        }
                    338: 
                    339:        if (ev->ev_events & EV_READ) {
                    340:                memset(&kev, 0, sizeof(kev));
                    341:                kev.ident = ev->ev_fd;
                    342:                kev.filter = EVFILT_READ;
                    343: #ifdef NOTE_EOF
                    344:                /* Make it behave like select() and poll() */
                    345:                kev.fflags = NOTE_EOF;
                    346: #endif
                    347:                kev.flags = EV_ADD;
                    348:                if (!(ev->ev_events & EV_PERSIST))
                    349:                        kev.flags |= EV_ONESHOT;
                    350:                kev.udata = PTR_TO_UDATA(ev);
                    351:                
                    352:                if (kq_insert(kqop, &kev) == -1)
                    353:                        return (-1);
                    354: 
                    355:                ev->ev_flags |= EVLIST_X_KQINKERNEL;
                    356:        }
                    357: 
                    358:        if (ev->ev_events & EV_WRITE) {
                    359:                memset(&kev, 0, sizeof(kev));
                    360:                kev.ident = ev->ev_fd;
                    361:                kev.filter = EVFILT_WRITE;
                    362:                kev.flags = EV_ADD;
                    363:                if (!(ev->ev_events & EV_PERSIST))
                    364:                        kev.flags |= EV_ONESHOT;
                    365:                kev.udata = PTR_TO_UDATA(ev);
                    366:                
                    367:                if (kq_insert(kqop, &kev) == -1)
                    368:                        return (-1);
                    369: 
                    370:                ev->ev_flags |= EVLIST_X_KQINKERNEL;
                    371:        }
                    372: 
                    373:        return (0);
                    374: }
                    375: 
                    376: static int
                    377: kq_del(void *arg, struct event *ev)
                    378: {
                    379:        struct kqop *kqop = arg;
                    380:        struct kevent kev;
                    381: 
                    382:        if (!(ev->ev_flags & EVLIST_X_KQINKERNEL))
                    383:                return (0);
                    384: 
                    385:        if (ev->ev_events & EV_SIGNAL) {
                    386:                int nsignal = EVENT_SIGNAL(ev);
                    387:                struct timespec timeout = { 0, 0 };
                    388: 
                    389:                assert(nsignal >= 0 && nsignal < NSIG);
                    390:                TAILQ_REMOVE(&kqop->evsigevents[nsignal], ev, ev_signal_next);
                    391:                if (TAILQ_EMPTY(&kqop->evsigevents[nsignal])) {
                    392:                        memset(&kev, 0, sizeof(kev));
                    393:                        kev.ident = nsignal;
                    394:                        kev.filter = EVFILT_SIGNAL;
                    395:                        kev.flags = EV_DELETE;
                    396:                
                    397:                        /* Because we insert signal events
                    398:                         * immediately, we need to delete them
                    399:                         * immediately, too */
                    400:                        if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
                    401:                                return (-1);
                    402: 
                    403:                        if (_evsignal_restore_handler(ev->ev_base,
                    404:                                nsignal) == -1)
                    405:                                return (-1);
                    406:                }
                    407: 
                    408:                ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
                    409:                return (0);
                    410:        }
                    411: 
                    412:        if (ev->ev_events & EV_READ) {
                    413:                memset(&kev, 0, sizeof(kev));
                    414:                kev.ident = ev->ev_fd;
                    415:                kev.filter = EVFILT_READ;
                    416:                kev.flags = EV_DELETE;
                    417:                
                    418:                if (kq_insert(kqop, &kev) == -1)
                    419:                        return (-1);
                    420: 
                    421:                ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
                    422:        }
                    423: 
                    424:        if (ev->ev_events & EV_WRITE) {
                    425:                memset(&kev, 0, sizeof(kev));
                    426:                kev.ident = ev->ev_fd;
                    427:                kev.filter = EVFILT_WRITE;
                    428:                kev.flags = EV_DELETE;
                    429:                
                    430:                if (kq_insert(kqop, &kev) == -1)
                    431:                        return (-1);
                    432: 
                    433:                ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
                    434:        }
                    435: 
                    436:        return (0);
                    437: }
                    438: 
                    439: static void
                    440: kq_dealloc(struct event_base *base, void *arg)
                    441: {
                    442:        struct kqop *kqop = arg;
                    443: 
                    444:        evsignal_dealloc(base);
                    445: 
                    446:        if (kqop->changes)
                    447:                free(kqop->changes);
                    448:        if (kqop->events)
                    449:                free(kqop->events);
                    450:        if (kqop->kq >= 0 && kqop->pid == getpid())
                    451:                close(kqop->kq);
                    452: 
                    453:        memset(kqop, 0, sizeof(struct kqop));
                    454:        free(kqop);
                    455: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>