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