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