1171169Smlaier/* $OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $ */ 2171169Smlaier 3171169Smlaier/* 4171169Smlaier * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu> 5171169Smlaier * All rights reserved. 6171169Smlaier * 7171169Smlaier * Redistribution and use in source and binary forms, with or without 8171169Smlaier * modification, are permitted provided that the following conditions 9171169Smlaier * are met: 10171169Smlaier * 1. Redistributions of source code must retain the above copyright 11171169Smlaier * notice, this list of conditions and the following disclaimer. 12171169Smlaier * 2. Redistributions in binary form must reproduce the above copyright 13171169Smlaier * notice, this list of conditions and the following disclaimer in the 14171169Smlaier * documentation and/or other materials provided with the distribution. 15171169Smlaier * 3. The name of the author may not be used to endorse or promote products 16171169Smlaier * derived from this software without specific prior written permission. 17171169Smlaier * 18171169Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19171169Smlaier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20171169Smlaier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21171169Smlaier * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22171169Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23171169Smlaier * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24171169Smlaier * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25171169Smlaier * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26171169Smlaier * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27171169Smlaier * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28171169Smlaier */ 29171169Smlaier#ifdef HAVE_CONFIG_H 30171169Smlaier#include "config.h" 31171169Smlaier#endif 32171169Smlaier 33171169Smlaier#include <sys/types.h> 34171169Smlaier#ifdef HAVE_SYS_TIME_H 35171169Smlaier#include <sys/time.h> 36171169Smlaier#else 37171169Smlaier#include <sys/_time.h> 38171169Smlaier#endif 39171169Smlaier#include <sys/queue.h> 40171169Smlaier#include <sys/event.h> 41171169Smlaier#include <signal.h> 42171169Smlaier#include <stdio.h> 43171169Smlaier#include <stdlib.h> 44171169Smlaier#include <string.h> 45171169Smlaier#include <unistd.h> 46171169Smlaier#include <errno.h> 47171169Smlaier#ifdef HAVE_INTTYPES_H 48171169Smlaier#include <inttypes.h> 49171169Smlaier#endif 50171169Smlaier 51171169Smlaier#if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) 52171169Smlaier#define INTPTR(x) (intptr_t)x 53171169Smlaier#else 54171169Smlaier#define INTPTR(x) x 55171169Smlaier#endif 56171169Smlaier 57171169Smlaier#include "event.h" 58171169Smlaier#include "log.h" 59171169Smlaier 60171169Smlaier#define EVLIST_X_KQINKERNEL 0x1000 61171169Smlaier 62171169Smlaier#define NEVENT 64 63171169Smlaier 64171169Smlaierstruct kqop { 65171169Smlaier struct kevent *changes; 66171169Smlaier int nchanges; 67171169Smlaier struct kevent *events; 68171169Smlaier int nevents; 69171169Smlaier int kq; 70171169Smlaier}; 71171169Smlaier 72171169Smlaiervoid *kq_init (void); 73171169Smlaierint kq_add (void *, struct event *); 74171169Smlaierint kq_del (void *, struct event *); 75171169Smlaierint kq_recalc (struct event_base *, void *, int); 76171169Smlaierint kq_dispatch (struct event_base *, void *, struct timeval *); 77171169Smlaierint kq_insert (struct kqop *, struct kevent *); 78171169Smlaiervoid kq_dealloc (void *); 79171169Smlaier 80171169Smlaierconst struct eventop kqops = { 81171169Smlaier "kqueue", 82171169Smlaier kq_init, 83171169Smlaier kq_add, 84171169Smlaier kq_del, 85171169Smlaier kq_recalc, 86171169Smlaier kq_dispatch, 87171169Smlaier kq_dealloc 88171169Smlaier}; 89171169Smlaier 90171169Smlaiervoid * 91171169Smlaierkq_init(void) 92171169Smlaier{ 93171169Smlaier int kq; 94171169Smlaier struct kqop *kqueueop; 95171169Smlaier 96171169Smlaier /* Disable kqueue when this environment variable is set */ 97171169Smlaier if (getenv("EVENT_NOKQUEUE")) 98171169Smlaier return (NULL); 99171169Smlaier 100171169Smlaier if (!(kqueueop = calloc(1, sizeof(struct kqop)))) 101171169Smlaier return (NULL); 102171169Smlaier 103171169Smlaier /* Initalize the kernel queue */ 104171169Smlaier 105171169Smlaier if ((kq = kqueue()) == -1) { 106171169Smlaier event_warn("kqueue"); 107171169Smlaier free (kqueueop); 108171169Smlaier return (NULL); 109171169Smlaier } 110171169Smlaier 111171169Smlaier kqueueop->kq = kq; 112171169Smlaier 113171169Smlaier /* Initalize fields */ 114171169Smlaier kqueueop->changes = malloc(NEVENT * sizeof(struct kevent)); 115171169Smlaier if (kqueueop->changes == NULL) { 116171169Smlaier free (kqueueop); 117171169Smlaier return (NULL); 118171169Smlaier } 119171169Smlaier kqueueop->events = malloc(NEVENT * sizeof(struct kevent)); 120171169Smlaier if (kqueueop->events == NULL) { 121171169Smlaier free (kqueueop->changes); 122171169Smlaier free (kqueueop); 123171169Smlaier return (NULL); 124171169Smlaier } 125171169Smlaier kqueueop->nevents = NEVENT; 126171169Smlaier 127171169Smlaier /* Check for Mac OS X kqueue bug. */ 128171169Smlaier kqueueop->changes[0].ident = -1; 129171169Smlaier kqueueop->changes[0].filter = EVFILT_READ; 130171169Smlaier kqueueop->changes[0].flags = EV_ADD; 131171169Smlaier /* 132171169Smlaier * If kqueue works, then kevent will succeed, and it will 133171169Smlaier * stick an error in events[0]. If kqueue is broken, then 134171169Smlaier * kevent will fail. 135171169Smlaier */ 136171169Smlaier if (kevent(kq, 137171169Smlaier kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 || 138171169Smlaier kqueueop->events[0].ident != -1 || 139171169Smlaier kqueueop->events[0].flags != EV_ERROR) { 140171169Smlaier event_warn("%s: detected broken kqueue; not using.", __func__); 141171169Smlaier free(kqueueop->changes); 142171169Smlaier free(kqueueop->events); 143171169Smlaier free(kqueueop); 144171169Smlaier close(kq); 145171169Smlaier return (NULL); 146171169Smlaier } 147171169Smlaier 148171169Smlaier return (kqueueop); 149171169Smlaier} 150171169Smlaier 151171169Smlaierint 152171169Smlaierkq_recalc(struct event_base *base, void *arg, int max) 153171169Smlaier{ 154171169Smlaier return (0); 155171169Smlaier} 156171169Smlaier 157171169Smlaierint 158171169Smlaierkq_insert(struct kqop *kqop, struct kevent *kev) 159171169Smlaier{ 160171169Smlaier int nevents = kqop->nevents; 161171169Smlaier 162171169Smlaier if (kqop->nchanges == nevents) { 163171169Smlaier struct kevent *newchange; 164171169Smlaier struct kevent *newresult; 165171169Smlaier 166171169Smlaier nevents *= 2; 167171169Smlaier 168171169Smlaier newchange = realloc(kqop->changes, 169171169Smlaier nevents * sizeof(struct kevent)); 170171169Smlaier if (newchange == NULL) { 171171169Smlaier event_warn("%s: malloc", __func__); 172171169Smlaier return (-1); 173171169Smlaier } 174171169Smlaier kqop->changes = newchange; 175171169Smlaier 176171169Smlaier newresult = realloc(kqop->events, 177171169Smlaier nevents * sizeof(struct kevent)); 178171169Smlaier 179171169Smlaier /* 180171169Smlaier * If we fail, we don't have to worry about freeing, 181171169Smlaier * the next realloc will pick it up. 182171169Smlaier */ 183171169Smlaier if (newresult == NULL) { 184171169Smlaier event_warn("%s: malloc", __func__); 185171169Smlaier return (-1); 186171169Smlaier } 187171169Smlaier kqop->events = newresult; 188171169Smlaier 189171169Smlaier kqop->nevents = nevents; 190171169Smlaier } 191171169Smlaier 192171169Smlaier memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent)); 193171169Smlaier 194171169Smlaier event_debug(("%s: fd %d %s%s", 195171169Smlaier __func__, kev->ident, 196171169Smlaier kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE", 197171169Smlaier kev->flags == EV_DELETE ? " (del)" : "")); 198171169Smlaier 199171169Smlaier return (0); 200171169Smlaier} 201171169Smlaier 202171169Smlaierstatic void 203171169Smlaierkq_sighandler(int sig) 204171169Smlaier{ 205171169Smlaier /* Do nothing here */ 206171169Smlaier} 207171169Smlaier 208171169Smlaierint 209171169Smlaierkq_dispatch(struct event_base *base, void *arg, struct timeval *tv) 210171169Smlaier{ 211171169Smlaier struct kqop *kqop = arg; 212171169Smlaier struct kevent *changes = kqop->changes; 213171169Smlaier struct kevent *events = kqop->events; 214171169Smlaier struct event *ev; 215171169Smlaier struct timespec ts; 216171169Smlaier int i, res; 217171169Smlaier 218171169Smlaier TIMEVAL_TO_TIMESPEC(tv, &ts); 219171169Smlaier 220171169Smlaier res = kevent(kqop->kq, changes, kqop->nchanges, 221171169Smlaier events, kqop->nevents, &ts); 222171169Smlaier kqop->nchanges = 0; 223171169Smlaier if (res == -1) { 224171169Smlaier if (errno != EINTR) { 225171169Smlaier event_warn("kevent"); 226171169Smlaier return (-1); 227171169Smlaier } 228171169Smlaier 229171169Smlaier return (0); 230171169Smlaier } 231171169Smlaier 232171169Smlaier event_debug(("%s: kevent reports %d", __func__, res)); 233171169Smlaier 234171169Smlaier for (i = 0; i < res; i++) { 235171169Smlaier int which = 0; 236171169Smlaier 237171169Smlaier if (events[i].flags & EV_ERROR) { 238171169Smlaier /* 239171169Smlaier * Error messages that can happen, when a delete fails. 240171169Smlaier * EBADF happens when the file discriptor has been 241171169Smlaier * closed, 242171169Smlaier * ENOENT when the file discriptor was closed and 243171169Smlaier * then reopened. 244171169Smlaier * EINVAL for some reasons not understood; EINVAL 245171169Smlaier * should not be returned ever; but FreeBSD does :-\ 246171169Smlaier * An error is also indicated when a callback deletes 247171169Smlaier * an event we are still processing. In that case 248171169Smlaier * the data field is set to ENOENT. 249171169Smlaier */ 250171169Smlaier if (events[i].data == EBADF || 251171169Smlaier events[i].data == EINVAL || 252171169Smlaier events[i].data == ENOENT) 253171169Smlaier continue; 254171169Smlaier errno = events[i].data; 255171169Smlaier return (-1); 256171169Smlaier } 257171169Smlaier 258171169Smlaier ev = (struct event *)events[i].udata; 259171169Smlaier 260171169Smlaier if (events[i].filter == EVFILT_READ) { 261171169Smlaier which |= EV_READ; 262171169Smlaier } else if (events[i].filter == EVFILT_WRITE) { 263171169Smlaier which |= EV_WRITE; 264171169Smlaier } else if (events[i].filter == EVFILT_SIGNAL) { 265171169Smlaier which |= EV_SIGNAL; 266171169Smlaier } 267171169Smlaier 268171169Smlaier if (!which) 269171169Smlaier continue; 270171169Smlaier 271171169Smlaier if (!(ev->ev_events & EV_PERSIST)) 272171169Smlaier event_del(ev); 273171169Smlaier 274171169Smlaier event_active(ev, which, 275171169Smlaier ev->ev_events & EV_SIGNAL ? events[i].data : 1); 276171169Smlaier } 277171169Smlaier 278171169Smlaier return (0); 279171169Smlaier} 280171169Smlaier 281171169Smlaier 282171169Smlaierint 283171169Smlaierkq_add(void *arg, struct event *ev) 284171169Smlaier{ 285171169Smlaier struct kqop *kqop = arg; 286171169Smlaier struct kevent kev; 287171169Smlaier 288171169Smlaier if (ev->ev_events & EV_SIGNAL) { 289171169Smlaier int nsignal = EVENT_SIGNAL(ev); 290171169Smlaier 291171169Smlaier memset(&kev, 0, sizeof(kev)); 292171169Smlaier kev.ident = nsignal; 293171169Smlaier kev.filter = EVFILT_SIGNAL; 294171169Smlaier kev.flags = EV_ADD; 295171169Smlaier if (!(ev->ev_events & EV_PERSIST)) 296171169Smlaier kev.flags |= EV_ONESHOT; 297171169Smlaier kev.udata = INTPTR(ev); 298171169Smlaier 299171169Smlaier if (kq_insert(kqop, &kev) == -1) 300171169Smlaier return (-1); 301171169Smlaier 302171169Smlaier if (signal(nsignal, kq_sighandler) == SIG_ERR) 303171169Smlaier return (-1); 304171169Smlaier 305171169Smlaier ev->ev_flags |= EVLIST_X_KQINKERNEL; 306171169Smlaier return (0); 307171169Smlaier } 308171169Smlaier 309171169Smlaier if (ev->ev_events & EV_READ) { 310171169Smlaier memset(&kev, 0, sizeof(kev)); 311171169Smlaier kev.ident = ev->ev_fd; 312171169Smlaier kev.filter = EVFILT_READ; 313171169Smlaier#ifdef NOTE_EOF 314171169Smlaier /* Make it behave like select() and poll() */ 315171169Smlaier kev.fflags = NOTE_EOF; 316171169Smlaier#endif 317171169Smlaier kev.flags = EV_ADD; 318171169Smlaier if (!(ev->ev_events & EV_PERSIST)) 319171169Smlaier kev.flags |= EV_ONESHOT; 320171169Smlaier kev.udata = INTPTR(ev); 321171169Smlaier 322171169Smlaier if (kq_insert(kqop, &kev) == -1) 323171169Smlaier return (-1); 324171169Smlaier 325171169Smlaier ev->ev_flags |= EVLIST_X_KQINKERNEL; 326171169Smlaier } 327171169Smlaier 328171169Smlaier if (ev->ev_events & EV_WRITE) { 329171169Smlaier memset(&kev, 0, sizeof(kev)); 330171169Smlaier kev.ident = ev->ev_fd; 331171169Smlaier kev.filter = EVFILT_WRITE; 332171169Smlaier kev.flags = EV_ADD; 333171169Smlaier if (!(ev->ev_events & EV_PERSIST)) 334171169Smlaier kev.flags |= EV_ONESHOT; 335171169Smlaier kev.udata = INTPTR(ev); 336171169Smlaier 337171169Smlaier if (kq_insert(kqop, &kev) == -1) 338171169Smlaier return (-1); 339171169Smlaier 340171169Smlaier ev->ev_flags |= EVLIST_X_KQINKERNEL; 341171169Smlaier } 342171169Smlaier 343171169Smlaier return (0); 344171169Smlaier} 345171169Smlaier 346171169Smlaierint 347171169Smlaierkq_del(void *arg, struct event *ev) 348171169Smlaier{ 349171169Smlaier struct kqop *kqop = arg; 350171169Smlaier struct kevent kev; 351171169Smlaier 352171169Smlaier if (!(ev->ev_flags & EVLIST_X_KQINKERNEL)) 353171169Smlaier return (0); 354171169Smlaier 355171169Smlaier if (ev->ev_events & EV_SIGNAL) { 356171169Smlaier int nsignal = EVENT_SIGNAL(ev); 357171169Smlaier 358171169Smlaier memset(&kev, 0, sizeof(kev)); 359171169Smlaier kev.ident = nsignal; 360171169Smlaier kev.filter = EVFILT_SIGNAL; 361171169Smlaier kev.flags = EV_DELETE; 362171169Smlaier 363171169Smlaier if (kq_insert(kqop, &kev) == -1) 364171169Smlaier return (-1); 365171169Smlaier 366171169Smlaier if (signal(nsignal, SIG_DFL) == SIG_ERR) 367171169Smlaier return (-1); 368171169Smlaier 369171169Smlaier ev->ev_flags &= ~EVLIST_X_KQINKERNEL; 370171169Smlaier return (0); 371171169Smlaier } 372171169Smlaier 373171169Smlaier if (ev->ev_events & EV_READ) { 374171169Smlaier memset(&kev, 0, sizeof(kev)); 375171169Smlaier kev.ident = ev->ev_fd; 376171169Smlaier kev.filter = EVFILT_READ; 377171169Smlaier kev.flags = EV_DELETE; 378171169Smlaier 379171169Smlaier if (kq_insert(kqop, &kev) == -1) 380171169Smlaier return (-1); 381171169Smlaier 382171169Smlaier ev->ev_flags &= ~EVLIST_X_KQINKERNEL; 383171169Smlaier } 384171169Smlaier 385171169Smlaier if (ev->ev_events & EV_WRITE) { 386171169Smlaier memset(&kev, 0, sizeof(kev)); 387171169Smlaier kev.ident = ev->ev_fd; 388171169Smlaier kev.filter = EVFILT_WRITE; 389171169Smlaier kev.flags = EV_DELETE; 390171169Smlaier 391171169Smlaier if (kq_insert(kqop, &kev) == -1) 392171169Smlaier return (-1); 393171169Smlaier 394171169Smlaier ev->ev_flags &= ~EVLIST_X_KQINKERNEL; 395171169Smlaier } 396171169Smlaier 397171169Smlaier return (0); 398171169Smlaier} 399171169Smlaier 400171169Smlaiervoid 401171169Smlaierkq_dealloc(void *arg) 402171169Smlaier{ 403171169Smlaier struct kqop *kqop = arg; 404171169Smlaier 405171169Smlaier if (kqop->changes) 406171169Smlaier free(kqop->changes); 407171169Smlaier if (kqop->events) 408171169Smlaier free(kqop->events); 409171169Smlaier if (kqop->kq) 410171169Smlaier close(kqop->kq); 411171169Smlaier memset(kqop, 0, sizeof(struct kqop)); 412171169Smlaier free(kqop); 413171169Smlaier} 414