1*ddb00dd9Sitojun /* $OpenBSD: kqueue.c,v 1.6 2002/09/08 07:52:33 itojun 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 */ 32fd332320Sprovos #include "config.h" 33fd332320Sprovos 34fd332320Sprovos #include <sys/types.h> 35fd332320Sprovos #include <sys/time.h> 36fd332320Sprovos #include <sys/queue.h> 37fd332320Sprovos #include <sys/event.h> 38fd332320Sprovos #include <signal.h> 39fd332320Sprovos #include <stdio.h> 40fd332320Sprovos #include <stdlib.h> 41ff33a3f0Sderaadt #include <string.h> 42fd332320Sprovos #include <unistd.h> 43fd332320Sprovos #include <errno.h> 44fd332320Sprovos 45fd332320Sprovos #ifdef USE_LOG 46fd332320Sprovos #include "log.h" 47fd332320Sprovos #else 48fd332320Sprovos #define LOG_DBG(x) 49fd332320Sprovos #define log_error(x) perror(x) 50fd332320Sprovos #endif 51fd332320Sprovos 52fd332320Sprovos #include "event.h" 53fd332320Sprovos 54fd332320Sprovos extern struct event_list timequeue; 55fd332320Sprovos extern struct event_list eventqueue; 56fd332320Sprovos extern struct event_list addqueue; 57fd332320Sprovos 58fd332320Sprovos #define EVLIST_X_KQINKERNEL 0x1000 59fd332320Sprovos 60fd332320Sprovos #define NEVENT 64 61fd332320Sprovos 62fd332320Sprovos struct kqop { 63fd332320Sprovos struct kevent *changes; 64fd332320Sprovos int nchanges; 65fd332320Sprovos struct kevent *events; 66fd332320Sprovos int nevents; 67fd332320Sprovos int kq; 68fd332320Sprovos } kqop; 69fd332320Sprovos 70fd332320Sprovos void *kq_init (void); 71fd332320Sprovos int kq_add (void *, struct event *); 72fd332320Sprovos int kq_del (void *, struct event *); 73fd332320Sprovos int kq_recalc (void *, int); 74fd332320Sprovos int kq_dispatch (void *, struct timeval *); 75fd332320Sprovos 76fd332320Sprovos struct eventop kqops = { 77fd332320Sprovos "kqueue", 78fd332320Sprovos kq_init, 79fd332320Sprovos kq_add, 80fd332320Sprovos kq_del, 81fd332320Sprovos kq_recalc, 82fd332320Sprovos kq_dispatch 83fd332320Sprovos }; 84fd332320Sprovos 85fd332320Sprovos void * 86fd332320Sprovos kq_init(void) 87fd332320Sprovos { 88fd332320Sprovos int kq; 89fd332320Sprovos 90fd332320Sprovos /* Disable kqueue when this environment variable is set */ 91fd332320Sprovos if (getenv("EVENT_NOKQUEUE")) 92fd332320Sprovos return (NULL); 93fd332320Sprovos 94fd332320Sprovos memset(&kqop, 0, sizeof(kqop)); 95fd332320Sprovos 96fd332320Sprovos /* Initalize the kernel queue */ 97fd332320Sprovos 98fd332320Sprovos if ((kq = kqueue()) == -1) { 99fd332320Sprovos log_error("kqueue"); 100fd332320Sprovos return (NULL); 101fd332320Sprovos } 102fd332320Sprovos 103fd332320Sprovos kqop.kq = kq; 104fd332320Sprovos 105fd332320Sprovos /* Initalize fields */ 106fd332320Sprovos kqop.changes = malloc(NEVENT * sizeof(struct kevent)); 107fd332320Sprovos if (kqop.changes == NULL) 108fd332320Sprovos return (NULL); 109fd332320Sprovos kqop.events = malloc(NEVENT * sizeof(struct kevent)); 110fd332320Sprovos if (kqop.events == NULL) { 111fd332320Sprovos free (kqop.changes); 112fd332320Sprovos return (NULL); 113fd332320Sprovos } 114fd332320Sprovos kqop.nevents = NEVENT; 115fd332320Sprovos 116fd332320Sprovos return (&kqop); 117fd332320Sprovos } 118fd332320Sprovos 119fd332320Sprovos int 120fd332320Sprovos kq_recalc(void *arg, int max) 121fd332320Sprovos { 122fd332320Sprovos return (0); 123fd332320Sprovos } 124fd332320Sprovos 125fd332320Sprovos int 126fd332320Sprovos kq_insert(struct kqop *kqop, struct kevent *kev) 127fd332320Sprovos { 128fd332320Sprovos int nevents = kqop->nevents; 129fd332320Sprovos 130fd332320Sprovos if (kqop->nchanges == nevents) { 131fd332320Sprovos struct kevent *newchange; 132fd332320Sprovos struct kevent *newresult; 133fd332320Sprovos 134fd332320Sprovos nevents *= 2; 135fd332320Sprovos 136fd332320Sprovos newchange = realloc(kqop->changes, 137fd332320Sprovos nevents * sizeof(struct kevent)); 138fd332320Sprovos if (newchange == NULL) { 139fd332320Sprovos log_error(__FUNCTION__": malloc"); 140fd332320Sprovos return (-1); 141fd332320Sprovos } 142fd332320Sprovos kqop->changes = newchange; 143fd332320Sprovos 144fd332320Sprovos newresult = realloc(kqop->changes, 145fd332320Sprovos nevents * sizeof(struct kevent)); 146fd332320Sprovos 147fd332320Sprovos /* 148fd332320Sprovos * If we fail, we don't have to worry about freeing, 149fd332320Sprovos * the next realloc will pick it up. 150fd332320Sprovos */ 151fd332320Sprovos if (newresult == NULL) { 152fd332320Sprovos log_error(__FUNCTION__": malloc"); 153fd332320Sprovos return (-1); 154fd332320Sprovos } 155fd332320Sprovos kqop->events = newchange; 156fd332320Sprovos 157fd332320Sprovos kqop->nevents = nevents; 158fd332320Sprovos } 159fd332320Sprovos 160fd332320Sprovos memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent)); 161fd332320Sprovos 162fd332320Sprovos LOG_DBG((LOG_MISC, 70, __FUNCTION__": fd %d %s%s", 163fd332320Sprovos kev->ident, 164fd332320Sprovos kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE", 165fd332320Sprovos kev->flags == EV_DELETE ? " (del)" : "")); 166fd332320Sprovos 167fd332320Sprovos return (0); 168fd332320Sprovos } 169fd332320Sprovos 170fd332320Sprovos static void 171fd332320Sprovos kq_sighandler(int sig) 172fd332320Sprovos { 173fd332320Sprovos /* Do nothing here */ 174fd332320Sprovos } 175fd332320Sprovos 176fd332320Sprovos int 177fd332320Sprovos kq_dispatch(void *arg, struct timeval *tv) 178fd332320Sprovos { 179fd332320Sprovos struct kqop *kqop = arg; 180fd332320Sprovos struct kevent *changes = kqop->changes; 181fd332320Sprovos struct kevent *events = kqop->events; 182fd332320Sprovos struct event *ev; 183fd332320Sprovos struct timespec ts; 184fd332320Sprovos int i, res; 185fd332320Sprovos 186fd332320Sprovos TIMEVAL_TO_TIMESPEC(tv, &ts); 187fd332320Sprovos 188fd332320Sprovos res = kevent(kqop->kq, changes, kqop->nchanges, 189fd332320Sprovos events, kqop->nevents, &ts); 190fd332320Sprovos kqop->nchanges = 0; 191fd332320Sprovos if (res == -1) { 192fd332320Sprovos if (errno != EINTR) { 193fd332320Sprovos log_error("kevent"); 194fd332320Sprovos return (-1); 195fd332320Sprovos } 196fd332320Sprovos 197fd332320Sprovos return (0); 198fd332320Sprovos } 199fd332320Sprovos 200fd332320Sprovos LOG_DBG((LOG_MISC, 80, __FUNCTION__": kevent reports %d", res)); 201fd332320Sprovos 202fd332320Sprovos for (i = 0; i < res; i++) { 203fd332320Sprovos int which = 0; 204fd332320Sprovos 205fd332320Sprovos if (events[i].flags & EV_ERROR) { 206fd332320Sprovos /* 207fd332320Sprovos * Error messages that can happen, when a delete fails. 208fd332320Sprovos * EBADF happens when the file discriptor has been 209fd332320Sprovos * closed, 210fd332320Sprovos * ENOENT when the file discriptor was closed and 211fd332320Sprovos * then reopened. 212fd332320Sprovos * An error is also indicated when a callback deletes 213fd332320Sprovos * an event we are still processing. In that case 214fd332320Sprovos * the data field is set to ENOENT. 215fd332320Sprovos */ 216fd332320Sprovos if (events[i].data == EBADF || 217fd332320Sprovos events[i].data == ENOENT) 218fd332320Sprovos continue; 219fd332320Sprovos return (-1); 220fd332320Sprovos } 221fd332320Sprovos 222fd332320Sprovos ev = events[i].udata; 223fd332320Sprovos 224fd332320Sprovos if (events[i].filter == EVFILT_READ) { 225fd332320Sprovos which |= EV_READ; 226fd332320Sprovos } else if (events[i].filter == EVFILT_WRITE) { 227fd332320Sprovos which |= EV_WRITE; 228fd332320Sprovos } else if (events[i].filter == EVFILT_SIGNAL) { 229fd332320Sprovos which |= EV_SIGNAL; 230fd332320Sprovos } else 231fd332320Sprovos events[i].filter = 0; 232fd332320Sprovos 233fd332320Sprovos if (!which) 234fd332320Sprovos continue; 235fd332320Sprovos 236fd332320Sprovos event_active(ev, which, 237fd332320Sprovos ev->ev_events & EV_SIGNAL ? events[i].data : 1); 238fd332320Sprovos } 239fd332320Sprovos 240fd332320Sprovos for (i = 0; i < res; i++) { 241fd332320Sprovos /* XXX */ 242a125e45cSprovos int ncalls, evres; 243fd332320Sprovos 244fd332320Sprovos if (events[i].flags & EV_ERROR || events[i].filter == NULL) 245fd332320Sprovos continue; 246fd332320Sprovos 247fd332320Sprovos ev = events[i].udata; 248fd332320Sprovos if (ev->ev_events & EV_PERSIST) 249fd332320Sprovos continue; 250fd332320Sprovos 251fd332320Sprovos ncalls = 0; 252fd332320Sprovos if (ev->ev_flags & EVLIST_ACTIVE) { 253fd332320Sprovos ncalls = ev->ev_ncalls; 254a125e45cSprovos evres = ev->ev_res; 255fd332320Sprovos } 256fd332320Sprovos ev->ev_flags &= ~EVLIST_X_KQINKERNEL; 257fd332320Sprovos event_del(ev); 258fd332320Sprovos 259fd332320Sprovos if (ncalls) 260a125e45cSprovos event_active(ev, evres, ncalls); 261fd332320Sprovos } 262fd332320Sprovos 263fd332320Sprovos return (0); 264fd332320Sprovos } 265fd332320Sprovos 266fd332320Sprovos 267fd332320Sprovos int 268fd332320Sprovos kq_add(void *arg, struct event *ev) 269fd332320Sprovos { 270fd332320Sprovos struct kqop *kqop = arg; 271fd332320Sprovos struct kevent kev; 272fd332320Sprovos 273fd332320Sprovos if (ev->ev_events & EV_SIGNAL) { 274fd332320Sprovos int nsignal = EVENT_SIGNAL(ev); 275fd332320Sprovos 276fd332320Sprovos memset(&kev, 0, sizeof(kev)); 277fd332320Sprovos kev.ident = nsignal; 278fd332320Sprovos kev.filter = EVFILT_SIGNAL; 279fd332320Sprovos kev.flags = EV_ADD; 280fd332320Sprovos if (!(ev->ev_events & EV_PERSIST)) 281*ddb00dd9Sitojun kev.flags |= EV_ONESHOT; 282fd332320Sprovos kev.udata = ev; 283fd332320Sprovos 284fd332320Sprovos if (kq_insert(kqop, &kev) == -1) 285fd332320Sprovos return (-1); 286fd332320Sprovos 287fd332320Sprovos if (signal(nsignal, kq_sighandler) == SIG_ERR) 288fd332320Sprovos return (-1); 289fd332320Sprovos 290fd332320Sprovos ev->ev_flags |= EVLIST_X_KQINKERNEL; 291fd332320Sprovos return (0); 292fd332320Sprovos } 293fd332320Sprovos 294fd332320Sprovos if (ev->ev_events & EV_READ) { 295fd332320Sprovos memset(&kev, 0, sizeof(kev)); 296fd332320Sprovos kev.ident = ev->ev_fd; 297fd332320Sprovos kev.filter = EVFILT_READ; 298e5c7daabSart kev.flags = EV_ADD; 299e5c7daabSart if (!(ev->ev_events & EV_PERSIST)) 300*ddb00dd9Sitojun kev.flags |= EV_ONESHOT; 301fd332320Sprovos kev.udata = ev; 302fd332320Sprovos 303fd332320Sprovos if (kq_insert(kqop, &kev) == -1) 304fd332320Sprovos return (-1); 305fd332320Sprovos 306fd332320Sprovos ev->ev_flags |= EVLIST_X_KQINKERNEL; 307fd332320Sprovos } 308fd332320Sprovos 309fd332320Sprovos if (ev->ev_events & EV_WRITE) { 310fd332320Sprovos memset(&kev, 0, sizeof(kev)); 311fd332320Sprovos kev.ident = ev->ev_fd; 312fd332320Sprovos kev.filter = EVFILT_WRITE; 313e5c7daabSart kev.flags = EV_ADD; 314e5c7daabSart if (!(ev->ev_events & EV_PERSIST)) 315*ddb00dd9Sitojun kev.flags |= EV_ONESHOT; 316fd332320Sprovos kev.udata = ev; 317fd332320Sprovos 318fd332320Sprovos if (kq_insert(kqop, &kev) == -1) 319fd332320Sprovos return (-1); 320fd332320Sprovos 321fd332320Sprovos ev->ev_flags |= EVLIST_X_KQINKERNEL; 322fd332320Sprovos } 323fd332320Sprovos 324fd332320Sprovos return (0); 325fd332320Sprovos } 326fd332320Sprovos 327fd332320Sprovos int 328fd332320Sprovos kq_del(void *arg, struct event *ev) 329fd332320Sprovos { 330fd332320Sprovos struct kqop *kqop = arg; 331fd332320Sprovos struct kevent kev; 332fd332320Sprovos 333fd332320Sprovos if (!(ev->ev_flags & EVLIST_X_KQINKERNEL)) 334fd332320Sprovos return (0); 335fd332320Sprovos 336fd332320Sprovos if (ev->ev_events & EV_SIGNAL) { 337fd332320Sprovos int nsignal = EVENT_SIGNAL(ev); 338fd332320Sprovos 339fd332320Sprovos memset(&kev, 0, sizeof(kev)); 340fd332320Sprovos kev.ident = (int)signal; 341fd332320Sprovos kev.filter = EVFILT_SIGNAL; 342fd332320Sprovos kev.flags = EV_DELETE; 343fd332320Sprovos 344fd332320Sprovos if (kq_insert(kqop, &kev) == -1) 345fd332320Sprovos return (-1); 346fd332320Sprovos 347fd332320Sprovos if (signal(nsignal, SIG_DFL) == SIG_ERR) 348fd332320Sprovos return (-1); 349fd332320Sprovos 350fd332320Sprovos ev->ev_flags &= ~EVLIST_X_KQINKERNEL; 351fd332320Sprovos return (0); 352fd332320Sprovos } 353fd332320Sprovos 354fd332320Sprovos if (ev->ev_events & EV_READ) { 355fd332320Sprovos memset(&kev, 0, sizeof(kev)); 356fd332320Sprovos kev.ident = ev->ev_fd; 357fd332320Sprovos kev.filter = EVFILT_READ; 358fd332320Sprovos kev.flags = EV_DELETE; 359fd332320Sprovos 360fd332320Sprovos if (kq_insert(kqop, &kev) == -1) 361fd332320Sprovos return (-1); 362fd332320Sprovos 363fd332320Sprovos ev->ev_flags &= ~EVLIST_X_KQINKERNEL; 364fd332320Sprovos } 365fd332320Sprovos 366fd332320Sprovos if (ev->ev_events & EV_WRITE) { 367fd332320Sprovos memset(&kev, 0, sizeof(kev)); 368fd332320Sprovos kev.ident = ev->ev_fd; 369fd332320Sprovos kev.filter = EVFILT_WRITE; 370fd332320Sprovos kev.flags = EV_DELETE; 371fd332320Sprovos 372fd332320Sprovos if (kq_insert(kqop, &kev) == -1) 373fd332320Sprovos return (-1); 374fd332320Sprovos 375fd332320Sprovos ev->ev_flags &= ~EVLIST_X_KQINKERNEL; 376fd332320Sprovos } 377fd332320Sprovos 378fd332320Sprovos return (0); 379fd332320Sprovos } 380