1*4643be29Sbrad /* $OpenBSD: kqueue.c,v 1.15 2005/04/22 00:56:25 brad Exp $ */ 234fc9cdeSmickey 3fd332320Sprovos /* 4fd332320Sprovos * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu> 5fd332320Sprovos * All rights reserved. 6fd332320Sprovos * 7fd332320Sprovos * Redistribution and use in source and binary forms, with or without 8fd332320Sprovos * modification, are permitted provided that the following conditions 9fd332320Sprovos * are met: 10fd332320Sprovos * 1. Redistributions of source code must retain the above copyright 11fd332320Sprovos * notice, this list of conditions and the following disclaimer. 12fd332320Sprovos * 2. Redistributions in binary form must reproduce the above copyright 13fd332320Sprovos * notice, this list of conditions and the following disclaimer in the 14fd332320Sprovos * documentation and/or other materials provided with the distribution. 15ff9272daSbrad * 3. The name of the author may not be used to endorse or promote products 16fd332320Sprovos * derived from this software without specific prior written permission. 17fd332320Sprovos * 18fd332320Sprovos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19fd332320Sprovos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20fd332320Sprovos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21fd332320Sprovos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22fd332320Sprovos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23fd332320Sprovos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24fd332320Sprovos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25fd332320Sprovos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26fd332320Sprovos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27fd332320Sprovos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28fd332320Sprovos */ 291770acb2Smarkus #ifdef HAVE_CONFIG_H 30fd332320Sprovos #include "config.h" 311770acb2Smarkus #endif 32fd332320Sprovos 33fd332320Sprovos #include <sys/types.h> 341770acb2Smarkus #ifdef HAVE_SYS_TIME_H 35fd332320Sprovos #include <sys/time.h> 361770acb2Smarkus #else 371770acb2Smarkus #include <sys/_time.h> 381770acb2Smarkus #endif 39fd332320Sprovos #include <sys/queue.h> 40fd332320Sprovos #include <sys/event.h> 41fd332320Sprovos #include <signal.h> 42fd332320Sprovos #include <stdio.h> 43fd332320Sprovos #include <stdlib.h> 44ff33a3f0Sderaadt #include <string.h> 45fd332320Sprovos #include <unistd.h> 46fd332320Sprovos #include <errno.h> 471770acb2Smarkus #ifdef HAVE_INTTYPES_H 481770acb2Smarkus #include <inttypes.h> 491770acb2Smarkus #endif 50fd332320Sprovos 51*4643be29Sbrad #if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) 521770acb2Smarkus #define INTPTR(x) (intptr_t)x 531770acb2Smarkus #else 541770acb2Smarkus #define INTPTR(x) x 55fd332320Sprovos #endif 56fd332320Sprovos 57fd332320Sprovos #include "event.h" 58*4643be29Sbrad #include "log.h" 59fd332320Sprovos 60fd332320Sprovos #define EVLIST_X_KQINKERNEL 0x1000 61fd332320Sprovos 62fd332320Sprovos #define NEVENT 64 63fd332320Sprovos 64fd332320Sprovos struct kqop { 65fd332320Sprovos struct kevent *changes; 66fd332320Sprovos int nchanges; 67fd332320Sprovos struct kevent *events; 68fd332320Sprovos int nevents; 69fd332320Sprovos int kq; 70*4643be29Sbrad }; 71fd332320Sprovos 72fd332320Sprovos void *kq_init (void); 73fd332320Sprovos int kq_add (void *, struct event *); 74fd332320Sprovos int kq_del (void *, struct event *); 75*4643be29Sbrad int kq_recalc (struct event_base *, void *, int); 76*4643be29Sbrad int kq_dispatch (struct event_base *, void *, struct timeval *); 77ff9272daSbrad int kq_insert (struct kqop *, struct kevent *); 78fd332320Sprovos 79759b8817Smickey const struct eventop kqops = { 80fd332320Sprovos "kqueue", 81fd332320Sprovos kq_init, 82fd332320Sprovos kq_add, 83fd332320Sprovos kq_del, 84fd332320Sprovos kq_recalc, 85fd332320Sprovos kq_dispatch 86fd332320Sprovos }; 87fd332320Sprovos 88fd332320Sprovos void * 89fd332320Sprovos kq_init(void) 90fd332320Sprovos { 91fd332320Sprovos int kq; 92*4643be29Sbrad struct kqop *kqueueop; 93fd332320Sprovos 94fd332320Sprovos /* Disable kqueue when this environment variable is set */ 951770acb2Smarkus if (!issetugid() && getenv("EVENT_NOKQUEUE")) 96fd332320Sprovos return (NULL); 97fd332320Sprovos 98*4643be29Sbrad if (!(kqueueop = calloc(1, sizeof(struct kqop)))) 99*4643be29Sbrad return (NULL); 100fd332320Sprovos 101ff9272daSbrad /* Initalize the kernel queue */ 102fd332320Sprovos 103fd332320Sprovos if ((kq = kqueue()) == -1) { 104*4643be29Sbrad event_warn("kqueue"); 105*4643be29Sbrad free (kqueueop); 106fd332320Sprovos return (NULL); 107fd332320Sprovos } 108fd332320Sprovos 109*4643be29Sbrad kqueueop->kq = kq; 110fd332320Sprovos 111ff9272daSbrad /* Initalize fields */ 112*4643be29Sbrad kqueueop->changes = malloc(NEVENT * sizeof(struct kevent)); 113*4643be29Sbrad if (kqueueop->changes == NULL) { 114*4643be29Sbrad free (kqueueop); 115fd332320Sprovos return (NULL); 116fd332320Sprovos } 117*4643be29Sbrad kqueueop->events = malloc(NEVENT * sizeof(struct kevent)); 118*4643be29Sbrad if (kqueueop->events == NULL) { 119*4643be29Sbrad free (kqueueop->changes); 120*4643be29Sbrad free (kqueueop); 121*4643be29Sbrad return (NULL); 122*4643be29Sbrad } 123*4643be29Sbrad kqueueop->nevents = NEVENT; 124fd332320Sprovos 125*4643be29Sbrad return (kqueueop); 126fd332320Sprovos } 127fd332320Sprovos 128fd332320Sprovos int 129*4643be29Sbrad kq_recalc(struct event_base *base, void *arg, int max) 130fd332320Sprovos { 131fd332320Sprovos return (0); 132fd332320Sprovos } 133fd332320Sprovos 134fd332320Sprovos int 135fd332320Sprovos kq_insert(struct kqop *kqop, struct kevent *kev) 136fd332320Sprovos { 137fd332320Sprovos int nevents = kqop->nevents; 138fd332320Sprovos 139fd332320Sprovos if (kqop->nchanges == nevents) { 140fd332320Sprovos struct kevent *newchange; 141fd332320Sprovos struct kevent *newresult; 142fd332320Sprovos 143fd332320Sprovos nevents *= 2; 144fd332320Sprovos 145fd332320Sprovos newchange = realloc(kqop->changes, 146fd332320Sprovos nevents * sizeof(struct kevent)); 147fd332320Sprovos if (newchange == NULL) { 148*4643be29Sbrad event_warn("%s: malloc", __func__); 149fd332320Sprovos return (-1); 150fd332320Sprovos } 151fd332320Sprovos kqop->changes = newchange; 152fd332320Sprovos 153ff9272daSbrad newresult = realloc(kqop->events, 154fd332320Sprovos nevents * sizeof(struct kevent)); 155fd332320Sprovos 156fd332320Sprovos /* 157fd332320Sprovos * If we fail, we don't have to worry about freeing, 158fd332320Sprovos * the next realloc will pick it up. 159fd332320Sprovos */ 160fd332320Sprovos if (newresult == NULL) { 161*4643be29Sbrad event_warn("%s: malloc", __func__); 162fd332320Sprovos return (-1); 163fd332320Sprovos } 164ff9272daSbrad kqop->events = newresult; 165fd332320Sprovos 166fd332320Sprovos kqop->nevents = nevents; 167fd332320Sprovos } 168fd332320Sprovos 169fd332320Sprovos memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent)); 170fd332320Sprovos 171*4643be29Sbrad event_debug(("%s: fd %d %s%s", 1721770acb2Smarkus __func__, kev->ident, 173fd332320Sprovos kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE", 174fd332320Sprovos kev->flags == EV_DELETE ? " (del)" : "")); 175fd332320Sprovos 176fd332320Sprovos return (0); 177fd332320Sprovos } 178fd332320Sprovos 179fd332320Sprovos static void 180fd332320Sprovos kq_sighandler(int sig) 181fd332320Sprovos { 182fd332320Sprovos /* Do nothing here */ 183fd332320Sprovos } 184fd332320Sprovos 185fd332320Sprovos int 186*4643be29Sbrad kq_dispatch(struct event_base *base, void *arg, struct timeval *tv) 187fd332320Sprovos { 188fd332320Sprovos struct kqop *kqop = arg; 189fd332320Sprovos struct kevent *changes = kqop->changes; 190fd332320Sprovos struct kevent *events = kqop->events; 191fd332320Sprovos struct event *ev; 192fd332320Sprovos struct timespec ts; 193fd332320Sprovos int i, res; 194fd332320Sprovos 195fd332320Sprovos TIMEVAL_TO_TIMESPEC(tv, &ts); 196fd332320Sprovos 197fd332320Sprovos res = kevent(kqop->kq, changes, kqop->nchanges, 198fd332320Sprovos events, kqop->nevents, &ts); 199fd332320Sprovos kqop->nchanges = 0; 200fd332320Sprovos if (res == -1) { 201fd332320Sprovos if (errno != EINTR) { 202*4643be29Sbrad event_warn("kevent"); 203fd332320Sprovos return (-1); 204fd332320Sprovos } 205fd332320Sprovos 206fd332320Sprovos return (0); 207fd332320Sprovos } 208fd332320Sprovos 209*4643be29Sbrad event_debug(("%s: kevent reports %d", __func__, res)); 210fd332320Sprovos 211fd332320Sprovos for (i = 0; i < res; i++) { 212fd332320Sprovos int which = 0; 213fd332320Sprovos 214fd332320Sprovos if (events[i].flags & EV_ERROR) { 215fd332320Sprovos /* 216fd332320Sprovos * Error messages that can happen, when a delete fails. 217fd332320Sprovos * EBADF happens when the file discriptor has been 218fd332320Sprovos * closed, 219fd332320Sprovos * ENOENT when the file discriptor was closed and 220fd332320Sprovos * then reopened. 221fd332320Sprovos * An error is also indicated when a callback deletes 222fd332320Sprovos * an event we are still processing. In that case 223fd332320Sprovos * the data field is set to ENOENT. 224fd332320Sprovos */ 225fd332320Sprovos if (events[i].data == EBADF || 226fd332320Sprovos events[i].data == ENOENT) 227fd332320Sprovos continue; 228fd332320Sprovos return (-1); 229fd332320Sprovos } 230fd332320Sprovos 2311770acb2Smarkus ev = (struct event *)events[i].udata; 232fd332320Sprovos 233fd332320Sprovos if (events[i].filter == EVFILT_READ) { 234fd332320Sprovos which |= EV_READ; 235fd332320Sprovos } else if (events[i].filter == EVFILT_WRITE) { 236fd332320Sprovos which |= EV_WRITE; 237fd332320Sprovos } else if (events[i].filter == EVFILT_SIGNAL) { 238fd332320Sprovos which |= EV_SIGNAL; 2391770acb2Smarkus } 240fd332320Sprovos 241fd332320Sprovos if (!which) 242fd332320Sprovos continue; 243fd332320Sprovos 2441770acb2Smarkus if (!(ev->ev_events & EV_PERSIST)) { 245fd332320Sprovos ev->ev_flags &= ~EVLIST_X_KQINKERNEL; 246fd332320Sprovos event_del(ev); 2471770acb2Smarkus } 248fd332320Sprovos 2491770acb2Smarkus event_active(ev, which, 2501770acb2Smarkus ev->ev_events & EV_SIGNAL ? events[i].data : 1); 251fd332320Sprovos } 252fd332320Sprovos 253fd332320Sprovos return (0); 254fd332320Sprovos } 255fd332320Sprovos 256fd332320Sprovos 257fd332320Sprovos int 258fd332320Sprovos kq_add(void *arg, struct event *ev) 259fd332320Sprovos { 260fd332320Sprovos struct kqop *kqop = arg; 261fd332320Sprovos struct kevent kev; 262fd332320Sprovos 263fd332320Sprovos if (ev->ev_events & EV_SIGNAL) { 264fd332320Sprovos int nsignal = EVENT_SIGNAL(ev); 265fd332320Sprovos 266fd332320Sprovos memset(&kev, 0, sizeof(kev)); 267fd332320Sprovos kev.ident = nsignal; 268fd332320Sprovos kev.filter = EVFILT_SIGNAL; 269fd332320Sprovos kev.flags = EV_ADD; 270fd332320Sprovos if (!(ev->ev_events & EV_PERSIST)) 271ddb00dd9Sitojun kev.flags |= EV_ONESHOT; 2721770acb2Smarkus kev.udata = INTPTR(ev); 273fd332320Sprovos 274fd332320Sprovos if (kq_insert(kqop, &kev) == -1) 275fd332320Sprovos return (-1); 276fd332320Sprovos 277fd332320Sprovos if (signal(nsignal, kq_sighandler) == SIG_ERR) 278fd332320Sprovos return (-1); 279fd332320Sprovos 280fd332320Sprovos ev->ev_flags |= EVLIST_X_KQINKERNEL; 281fd332320Sprovos return (0); 282fd332320Sprovos } 283fd332320Sprovos 284fd332320Sprovos if (ev->ev_events & EV_READ) { 285fd332320Sprovos memset(&kev, 0, sizeof(kev)); 286fd332320Sprovos kev.ident = ev->ev_fd; 287fd332320Sprovos kev.filter = EVFILT_READ; 288ff9272daSbrad #ifdef NOTE_EOF 289c74e3f8eSmarkus /* Make it behave like select() and poll() */ 290c74e3f8eSmarkus kev.fflags = NOTE_EOF; 291ff9272daSbrad #endif 292ff9272daSbrad kev.flags = EV_ADD; 293e5c7daabSart if (!(ev->ev_events & EV_PERSIST)) 294ddb00dd9Sitojun kev.flags |= EV_ONESHOT; 2951770acb2Smarkus kev.udata = INTPTR(ev); 296fd332320Sprovos 297fd332320Sprovos if (kq_insert(kqop, &kev) == -1) 298fd332320Sprovos return (-1); 299fd332320Sprovos 300fd332320Sprovos ev->ev_flags |= EVLIST_X_KQINKERNEL; 301fd332320Sprovos } 302fd332320Sprovos 303fd332320Sprovos if (ev->ev_events & EV_WRITE) { 304fd332320Sprovos memset(&kev, 0, sizeof(kev)); 305fd332320Sprovos kev.ident = ev->ev_fd; 306fd332320Sprovos kev.filter = EVFILT_WRITE; 307e5c7daabSart kev.flags = EV_ADD; 308e5c7daabSart if (!(ev->ev_events & EV_PERSIST)) 309ddb00dd9Sitojun kev.flags |= EV_ONESHOT; 3101770acb2Smarkus kev.udata = INTPTR(ev); 311fd332320Sprovos 312fd332320Sprovos if (kq_insert(kqop, &kev) == -1) 313fd332320Sprovos return (-1); 314fd332320Sprovos 315fd332320Sprovos ev->ev_flags |= EVLIST_X_KQINKERNEL; 316fd332320Sprovos } 317fd332320Sprovos 318fd332320Sprovos return (0); 319fd332320Sprovos } 320fd332320Sprovos 321fd332320Sprovos int 322fd332320Sprovos kq_del(void *arg, struct event *ev) 323fd332320Sprovos { 324fd332320Sprovos struct kqop *kqop = arg; 325fd332320Sprovos struct kevent kev; 326fd332320Sprovos 327fd332320Sprovos if (!(ev->ev_flags & EVLIST_X_KQINKERNEL)) 328fd332320Sprovos return (0); 329fd332320Sprovos 330fd332320Sprovos if (ev->ev_events & EV_SIGNAL) { 331fd332320Sprovos int nsignal = EVENT_SIGNAL(ev); 332fd332320Sprovos 333fd332320Sprovos memset(&kev, 0, sizeof(kev)); 334fd332320Sprovos kev.ident = (int)signal; 335fd332320Sprovos kev.filter = EVFILT_SIGNAL; 336fd332320Sprovos kev.flags = EV_DELETE; 337fd332320Sprovos 338fd332320Sprovos if (kq_insert(kqop, &kev) == -1) 339fd332320Sprovos return (-1); 340fd332320Sprovos 341fd332320Sprovos if (signal(nsignal, SIG_DFL) == SIG_ERR) 342fd332320Sprovos return (-1); 343fd332320Sprovos 344fd332320Sprovos ev->ev_flags &= ~EVLIST_X_KQINKERNEL; 345fd332320Sprovos return (0); 346fd332320Sprovos } 347fd332320Sprovos 348fd332320Sprovos if (ev->ev_events & EV_READ) { 349fd332320Sprovos memset(&kev, 0, sizeof(kev)); 350fd332320Sprovos kev.ident = ev->ev_fd; 351fd332320Sprovos kev.filter = EVFILT_READ; 352fd332320Sprovos kev.flags = EV_DELETE; 353fd332320Sprovos 354fd332320Sprovos if (kq_insert(kqop, &kev) == -1) 355fd332320Sprovos return (-1); 356fd332320Sprovos 357fd332320Sprovos ev->ev_flags &= ~EVLIST_X_KQINKERNEL; 358fd332320Sprovos } 359fd332320Sprovos 360fd332320Sprovos if (ev->ev_events & EV_WRITE) { 361fd332320Sprovos memset(&kev, 0, sizeof(kev)); 362fd332320Sprovos kev.ident = ev->ev_fd; 363fd332320Sprovos kev.filter = EVFILT_WRITE; 364fd332320Sprovos kev.flags = EV_DELETE; 365fd332320Sprovos 366fd332320Sprovos if (kq_insert(kqop, &kev) == -1) 367fd332320Sprovos return (-1); 368fd332320Sprovos 369fd332320Sprovos ev->ev_flags &= ~EVLIST_X_KQINKERNEL; 370fd332320Sprovos } 371fd332320Sprovos 372fd332320Sprovos return (0); 373fd332320Sprovos } 374