1 1.6 christos /* $NetBSD: kqueue.c,v 1.7 2024/08/18 20:47:21 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* $OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $ */ 4 1.1 christos 5 1.1 christos /* 6 1.1 christos * Copyright 2000-2007 Niels Provos <provos (at) citi.umich.edu> 7 1.1 christos * Copyright 2007-2012 Niels Provos and Nick Mathewson 8 1.1 christos * 9 1.1 christos * Redistribution and use in source and binary forms, with or without 10 1.1 christos * modification, are permitted provided that the following conditions 11 1.1 christos * are met: 12 1.1 christos * 1. Redistributions of source code must retain the above copyright 13 1.1 christos * notice, this list of conditions and the following disclaimer. 14 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 christos * notice, this list of conditions and the following disclaimer in the 16 1.1 christos * documentation and/or other materials provided with the distribution. 17 1.1 christos * 3. The name of the author may not be used to endorse or promote products 18 1.1 christos * derived from this software without specific prior written permission. 19 1.1 christos * 20 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 1.1 christos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 1.1 christos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 1.1 christos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 1.1 christos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 1.1 christos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 1.1 christos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 1.1 christos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 1.1 christos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 1.1 christos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 1.1 christos */ 31 1.1 christos #include "event2/event-config.h" 32 1.1 christos #include "evconfig-private.h" 33 1.1 christos 34 1.1 christos #ifdef EVENT__HAVE_KQUEUE 35 1.1 christos 36 1.1 christos #include <sys/types.h> 37 1.1 christos #ifdef EVENT__HAVE_SYS_TIME_H 38 1.1 christos #include <sys/time.h> 39 1.1 christos #endif 40 1.1 christos #include <sys/queue.h> 41 1.1 christos #include <sys/event.h> 42 1.7 christos #include <limits.h> 43 1.1 christos #include <signal.h> 44 1.1 christos #include <stdio.h> 45 1.1 christos #include <stdlib.h> 46 1.1 christos #include <string.h> 47 1.1 christos #include <unistd.h> 48 1.1 christos #include <errno.h> 49 1.1 christos #ifdef EVENT__HAVE_INTTYPES_H 50 1.1 christos #include <inttypes.h> 51 1.1 christos #endif 52 1.1 christos 53 1.1 christos /* Some platforms apparently define the udata field of struct kevent as 54 1.1 christos * intptr_t, whereas others define it as void*. There doesn't seem to be an 55 1.1 christos * easy way to tell them apart via autoconf, so we need to use OS macros. */ 56 1.7 christos #if defined(__NetBSD__) 57 1.7 christos #define PTR_TO_UDATA(x) ((typeof(((struct kevent *)0)->udata))(x)) 58 1.7 christos #define INT_TO_UDATA(x) ((typeof(((struct kevent *)0)->udata))(intptr_t)(x)) 59 1.7 christos #elif defined(EVENT__HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__) && !defined(__CloudABI__) 60 1.1 christos #define PTR_TO_UDATA(x) ((intptr_t)(x)) 61 1.1 christos #define INT_TO_UDATA(x) ((intptr_t)(x)) 62 1.1 christos #else 63 1.1 christos #define PTR_TO_UDATA(x) (x) 64 1.1 christos #define INT_TO_UDATA(x) ((void*)(x)) 65 1.1 christos #endif 66 1.1 christos 67 1.1 christos #include "event-internal.h" 68 1.1 christos #include "log-internal.h" 69 1.1 christos #include "evmap-internal.h" 70 1.1 christos #include "event2/thread.h" 71 1.7 christos #include "event2/util.h" 72 1.1 christos #include "evthread-internal.h" 73 1.1 christos #include "changelist-internal.h" 74 1.1 christos 75 1.1 christos #include "kqueue-internal.h" 76 1.1 christos 77 1.1 christos #define NEVENT 64 78 1.1 christos 79 1.1 christos struct kqop { 80 1.1 christos struct kevent *changes; 81 1.1 christos int changes_size; 82 1.1 christos 83 1.1 christos struct kevent *events; 84 1.1 christos int events_size; 85 1.1 christos int kq; 86 1.1 christos int notify_event_added; 87 1.1 christos pid_t pid; 88 1.1 christos }; 89 1.1 christos 90 1.1 christos static void kqop_free(struct kqop *kqop); 91 1.1 christos 92 1.1 christos static void *kq_init(struct event_base *); 93 1.1 christos static int kq_sig_add(struct event_base *, int, short, short, void *); 94 1.1 christos static int kq_sig_del(struct event_base *, int, short, short, void *); 95 1.1 christos static int kq_dispatch(struct event_base *, struct timeval *); 96 1.1 christos static void kq_dealloc(struct event_base *); 97 1.1 christos 98 1.1 christos const struct eventop kqops = { 99 1.1 christos "kqueue", 100 1.1 christos kq_init, 101 1.1 christos event_changelist_add_, 102 1.1 christos event_changelist_del_, 103 1.1 christos kq_dispatch, 104 1.1 christos kq_dealloc, 105 1.1 christos 1 /* need reinit */, 106 1.1 christos EV_FEATURE_ET|EV_FEATURE_O1|EV_FEATURE_FDS, 107 1.1 christos EVENT_CHANGELIST_FDINFO_SIZE 108 1.1 christos }; 109 1.1 christos 110 1.1 christos static const struct eventop kqsigops = { 111 1.1 christos "kqueue_signal", 112 1.1 christos NULL, 113 1.1 christos kq_sig_add, 114 1.1 christos kq_sig_del, 115 1.1 christos NULL, 116 1.1 christos NULL, 117 1.1 christos 1 /* need reinit */, 118 1.1 christos 0, 119 1.1 christos 0 120 1.1 christos }; 121 1.1 christos 122 1.1 christos static void * 123 1.1 christos kq_init(struct event_base *base) 124 1.1 christos { 125 1.1 christos int kq = -1; 126 1.1 christos struct kqop *kqueueop = NULL; 127 1.1 christos 128 1.1 christos if (!(kqueueop = mm_calloc(1, sizeof(struct kqop)))) 129 1.1 christos return (NULL); 130 1.1 christos 131 1.1 christos /* Initialize the kernel queue */ 132 1.1 christos 133 1.1 christos if ((kq = kqueue()) == -1) { 134 1.1 christos event_warn("kqueue"); 135 1.1 christos goto err; 136 1.1 christos } 137 1.1 christos 138 1.1 christos kqueueop->kq = kq; 139 1.1 christos 140 1.1 christos kqueueop->pid = getpid(); 141 1.1 christos 142 1.1 christos /* Initialize fields */ 143 1.1 christos kqueueop->changes = mm_calloc(NEVENT, sizeof(struct kevent)); 144 1.1 christos if (kqueueop->changes == NULL) 145 1.1 christos goto err; 146 1.1 christos kqueueop->events = mm_calloc(NEVENT, sizeof(struct kevent)); 147 1.1 christos if (kqueueop->events == NULL) 148 1.1 christos goto err; 149 1.1 christos kqueueop->events_size = kqueueop->changes_size = NEVENT; 150 1.1 christos 151 1.1 christos /* Check for Mac OS X kqueue bug. */ 152 1.1 christos memset(&kqueueop->changes[0], 0, sizeof kqueueop->changes[0]); 153 1.1 christos kqueueop->changes[0].ident = -1; 154 1.1 christos kqueueop->changes[0].filter = EVFILT_READ; 155 1.1 christos kqueueop->changes[0].flags = EV_ADD; 156 1.1 christos /* 157 1.1 christos * If kqueue works, then kevent will succeed, and it will 158 1.1 christos * stick an error in events[0]. If kqueue is broken, then 159 1.1 christos * kevent will fail. 160 1.1 christos */ 161 1.1 christos if (kevent(kq, 162 1.1 christos kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 || 163 1.1 christos (int)kqueueop->events[0].ident != -1 || 164 1.7 christos !(kqueueop->events[0].flags & EV_ERROR)) { 165 1.1 christos event_warn("%s: detected broken kqueue; not using.", __func__); 166 1.1 christos goto err; 167 1.1 christos } 168 1.1 christos 169 1.1 christos base->evsigsel = &kqsigops; 170 1.1 christos 171 1.1 christos return (kqueueop); 172 1.1 christos err: 173 1.1 christos if (kqueueop) 174 1.1 christos kqop_free(kqueueop); 175 1.1 christos 176 1.1 christos return (NULL); 177 1.1 christos } 178 1.1 christos 179 1.1 christos #define ADD_UDATA 0x30303 180 1.1 christos 181 1.1 christos static void 182 1.1 christos kq_setup_kevent(struct kevent *out, evutil_socket_t fd, int filter, short change) 183 1.1 christos { 184 1.1 christos memset(out, 0, sizeof(struct kevent)); 185 1.1 christos out->ident = fd; 186 1.1 christos out->filter = filter; 187 1.1 christos 188 1.1 christos if (change & EV_CHANGE_ADD) { 189 1.1 christos out->flags = EV_ADD; 190 1.1 christos /* We set a magic number here so that we can tell 'add' 191 1.1 christos * errors from 'del' errors. */ 192 1.1 christos out->udata = INT_TO_UDATA(ADD_UDATA); 193 1.1 christos if (change & EV_ET) 194 1.1 christos out->flags |= EV_CLEAR; 195 1.1 christos #ifdef NOTE_EOF 196 1.1 christos /* Make it behave like select() and poll() */ 197 1.1 christos if (filter == EVFILT_READ) 198 1.1 christos out->fflags = NOTE_EOF; 199 1.1 christos #endif 200 1.1 christos } else { 201 1.1 christos EVUTIL_ASSERT(change & EV_CHANGE_DEL); 202 1.1 christos out->flags = EV_DELETE; 203 1.1 christos } 204 1.1 christos } 205 1.1 christos 206 1.1 christos static int 207 1.1 christos kq_build_changes_list(const struct event_changelist *changelist, 208 1.1 christos struct kqop *kqop) 209 1.1 christos { 210 1.1 christos int i; 211 1.1 christos int n_changes = 0; 212 1.1 christos 213 1.1 christos for (i = 0; i < changelist->n_changes; ++i) { 214 1.1 christos struct event_change *in_ch = &changelist->changes[i]; 215 1.1 christos struct kevent *out_ch; 216 1.1 christos if (n_changes >= kqop->changes_size - 1) { 217 1.7 christos int newsize; 218 1.1 christos struct kevent *newchanges; 219 1.1 christos 220 1.7 christos if (kqop->changes_size > INT_MAX / 2 || 221 1.7 christos (size_t)kqop->changes_size * 2 > EV_SIZE_MAX / 222 1.7 christos sizeof(struct kevent)) { 223 1.7 christos event_warnx("%s: int overflow", __func__); 224 1.7 christos return (-1); 225 1.7 christos } 226 1.7 christos 227 1.7 christos newsize = kqop->changes_size * 2; 228 1.1 christos newchanges = mm_realloc(kqop->changes, 229 1.1 christos newsize * sizeof(struct kevent)); 230 1.1 christos if (newchanges == NULL) { 231 1.1 christos event_warn("%s: realloc", __func__); 232 1.1 christos return (-1); 233 1.1 christos } 234 1.1 christos kqop->changes = newchanges; 235 1.1 christos kqop->changes_size = newsize; 236 1.1 christos } 237 1.1 christos if (in_ch->read_change) { 238 1.1 christos out_ch = &kqop->changes[n_changes++]; 239 1.1 christos kq_setup_kevent(out_ch, in_ch->fd, EVFILT_READ, 240 1.1 christos in_ch->read_change); 241 1.1 christos } 242 1.1 christos if (in_ch->write_change) { 243 1.1 christos out_ch = &kqop->changes[n_changes++]; 244 1.1 christos kq_setup_kevent(out_ch, in_ch->fd, EVFILT_WRITE, 245 1.1 christos in_ch->write_change); 246 1.1 christos } 247 1.1 christos } 248 1.1 christos return n_changes; 249 1.1 christos } 250 1.1 christos 251 1.1 christos static int 252 1.1 christos kq_grow_events(struct kqop *kqop, size_t new_size) 253 1.1 christos { 254 1.1 christos struct kevent *newresult; 255 1.1 christos 256 1.1 christos newresult = mm_realloc(kqop->events, 257 1.1 christos new_size * sizeof(struct kevent)); 258 1.1 christos 259 1.1 christos if (newresult) { 260 1.1 christos kqop->events = newresult; 261 1.1 christos kqop->events_size = new_size; 262 1.1 christos return 0; 263 1.1 christos } else { 264 1.1 christos return -1; 265 1.1 christos } 266 1.1 christos } 267 1.1 christos 268 1.1 christos static int 269 1.1 christos kq_dispatch(struct event_base *base, struct timeval *tv) 270 1.1 christos { 271 1.1 christos struct kqop *kqop = base->evbase; 272 1.1 christos struct kevent *events = kqop->events; 273 1.1 christos struct kevent *changes; 274 1.1 christos struct timespec ts, *ts_p = NULL; 275 1.1 christos int i, n_changes, res; 276 1.1 christos 277 1.1 christos if (tv != NULL) { 278 1.7 christos ts.tv_sec = tv->tv_sec; 279 1.7 christos ts.tv_nsec = tv->tv_usec * 1000; 280 1.1 christos ts_p = &ts; 281 1.1 christos } 282 1.1 christos 283 1.1 christos /* Build "changes" from "base->changes" */ 284 1.1 christos EVUTIL_ASSERT(kqop->changes); 285 1.1 christos n_changes = kq_build_changes_list(&base->changelist, kqop); 286 1.1 christos if (n_changes < 0) 287 1.1 christos return -1; 288 1.1 christos 289 1.1 christos event_changelist_remove_all_(&base->changelist, base); 290 1.1 christos 291 1.1 christos /* steal the changes array in case some broken code tries to call 292 1.1 christos * dispatch twice at once. */ 293 1.1 christos changes = kqop->changes; 294 1.1 christos kqop->changes = NULL; 295 1.1 christos 296 1.1 christos /* Make sure that 'events' is at least as long as the list of changes: 297 1.1 christos * otherwise errors in the changes can get reported as a -1 return 298 1.1 christos * value from kevent() rather than as EV_ERROR events in the events 299 1.1 christos * array. 300 1.1 christos * 301 1.1 christos * (We could instead handle -1 return values from kevent() by 302 1.1 christos * retrying with a smaller changes array or a larger events array, 303 1.1 christos * but this approach seems less risky for now.) 304 1.1 christos */ 305 1.1 christos if (kqop->events_size < n_changes) { 306 1.1 christos int new_size = kqop->events_size; 307 1.1 christos do { 308 1.1 christos new_size *= 2; 309 1.1 christos } while (new_size < n_changes); 310 1.1 christos 311 1.1 christos kq_grow_events(kqop, new_size); 312 1.1 christos events = kqop->events; 313 1.1 christos } 314 1.1 christos 315 1.1 christos EVBASE_RELEASE_LOCK(base, th_base_lock); 316 1.1 christos 317 1.1 christos res = kevent(kqop->kq, changes, n_changes, 318 1.1 christos events, kqop->events_size, ts_p); 319 1.1 christos 320 1.1 christos EVBASE_ACQUIRE_LOCK(base, th_base_lock); 321 1.1 christos 322 1.1 christos EVUTIL_ASSERT(kqop->changes == NULL); 323 1.1 christos kqop->changes = changes; 324 1.1 christos 325 1.1 christos if (res == -1) { 326 1.1 christos if (errno != EINTR) { 327 1.1 christos event_warn("kevent"); 328 1.1 christos return (-1); 329 1.1 christos } 330 1.1 christos 331 1.1 christos return (0); 332 1.1 christos } 333 1.1 christos 334 1.1 christos event_debug(("%s: kevent reports %d", __func__, res)); 335 1.1 christos 336 1.1 christos for (i = 0; i < res; i++) { 337 1.1 christos int which = 0; 338 1.1 christos 339 1.1 christos if (events[i].flags & EV_ERROR) { 340 1.1 christos switch (events[i].data) { 341 1.1 christos 342 1.1 christos /* Can occur on delete if we are not currently 343 1.1 christos * watching any events on this fd. That can 344 1.1 christos * happen when the fd was closed and another 345 1.1 christos * file was opened with that fd. */ 346 1.1 christos case ENOENT: 347 1.1 christos /* Can occur for reasons not fully understood 348 1.1 christos * on FreeBSD. */ 349 1.1 christos case EINVAL: 350 1.1 christos continue; 351 1.3 christos #if defined(__FreeBSD__) && defined(ENOTCAPABLE) 352 1.3 christos /* 353 1.3 christos * This currently occurs if an FD is closed 354 1.3 christos * before the EV_DELETE makes it out via kevent(). 355 1.3 christos * The FreeBSD capabilities code sees the blank 356 1.3 christos * capability set and rejects the request to 357 1.3 christos * modify an event. 358 1.3 christos * 359 1.3 christos * To be strictly correct - when an FD is closed, 360 1.3 christos * all the registered events are also removed. 361 1.3 christos * Queuing EV_DELETE to a closed FD is wrong. 362 1.3 christos * The event(s) should just be deleted from 363 1.3 christos * the pending changelist. 364 1.3 christos */ 365 1.3 christos case ENOTCAPABLE: 366 1.3 christos continue; 367 1.3 christos #endif 368 1.1 christos 369 1.1 christos /* Can occur on a delete if the fd is closed. */ 370 1.1 christos case EBADF: 371 1.1 christos /* XXXX On NetBSD, we can also get EBADF if we 372 1.1 christos * try to add the write side of a pipe, but 373 1.1 christos * the read side has already been closed. 374 1.1 christos * Other BSDs call this situation 'EPIPE'. It 375 1.1 christos * would be good if we had a way to report 376 1.1 christos * this situation. */ 377 1.1 christos continue; 378 1.1 christos /* These two can occur on an add if the fd was one side 379 1.1 christos * of a pipe, and the other side was closed. */ 380 1.1 christos case EPERM: 381 1.1 christos case EPIPE: 382 1.1 christos /* Report read events, if we're listening for 383 1.1 christos * them, so that the user can learn about any 384 1.1 christos * add errors. (If the operation was a 385 1.1 christos * delete, then udata should be cleared.) */ 386 1.1 christos if (events[i].udata) { 387 1.1 christos /* The operation was an add: 388 1.1 christos * report the error as a read. */ 389 1.1 christos which |= EV_READ; 390 1.1 christos break; 391 1.1 christos } else { 392 1.1 christos /* The operation was a del: 393 1.1 christos * report nothing. */ 394 1.1 christos continue; 395 1.1 christos } 396 1.1 christos 397 1.1 christos /* Other errors shouldn't occur. */ 398 1.1 christos default: 399 1.1 christos errno = events[i].data; 400 1.1 christos return (-1); 401 1.1 christos } 402 1.1 christos } else if (events[i].filter == EVFILT_READ) { 403 1.1 christos which |= EV_READ; 404 1.1 christos } else if (events[i].filter == EVFILT_WRITE) { 405 1.1 christos which |= EV_WRITE; 406 1.1 christos } else if (events[i].filter == EVFILT_SIGNAL) { 407 1.1 christos which |= EV_SIGNAL; 408 1.1 christos #ifdef EVFILT_USER 409 1.1 christos } else if (events[i].filter == EVFILT_USER) { 410 1.1 christos base->is_notify_pending = 0; 411 1.1 christos #endif 412 1.1 christos } 413 1.1 christos 414 1.1 christos if (!which) 415 1.1 christos continue; 416 1.1 christos 417 1.1 christos if (events[i].filter == EVFILT_SIGNAL) { 418 1.1 christos evmap_signal_active_(base, events[i].ident, 1); 419 1.1 christos } else { 420 1.1 christos evmap_io_active_(base, events[i].ident, which | EV_ET); 421 1.1 christos } 422 1.1 christos } 423 1.1 christos 424 1.1 christos if (res == kqop->events_size) { 425 1.1 christos /* We used all the events space that we have. Maybe we should 426 1.1 christos make it bigger. */ 427 1.1 christos kq_grow_events(kqop, kqop->events_size * 2); 428 1.1 christos } 429 1.1 christos 430 1.1 christos return (0); 431 1.1 christos } 432 1.1 christos 433 1.1 christos static void 434 1.1 christos kqop_free(struct kqop *kqop) 435 1.1 christos { 436 1.1 christos if (kqop->changes) 437 1.1 christos mm_free(kqop->changes); 438 1.1 christos if (kqop->events) 439 1.1 christos mm_free(kqop->events); 440 1.1 christos if (kqop->kq >= 0 && kqop->pid == getpid()) 441 1.1 christos close(kqop->kq); 442 1.1 christos memset(kqop, 0, sizeof(struct kqop)); 443 1.1 christos mm_free(kqop); 444 1.1 christos } 445 1.1 christos 446 1.1 christos static void 447 1.1 christos kq_dealloc(struct event_base *base) 448 1.1 christos { 449 1.1 christos struct kqop *kqop = base->evbase; 450 1.1 christos evsig_dealloc_(base); 451 1.1 christos kqop_free(kqop); 452 1.1 christos } 453 1.1 christos 454 1.1 christos /* signal handling */ 455 1.1 christos static int 456 1.1 christos kq_sig_add(struct event_base *base, int nsignal, short old, short events, void *p) 457 1.1 christos { 458 1.1 christos struct kqop *kqop = base->evbase; 459 1.1 christos struct kevent kev; 460 1.1 christos struct timespec timeout = { 0, 0 }; 461 1.1 christos (void)p; 462 1.1 christos 463 1.1 christos EVUTIL_ASSERT(nsignal >= 0 && nsignal < NSIG); 464 1.1 christos 465 1.1 christos memset(&kev, 0, sizeof(kev)); 466 1.1 christos kev.ident = nsignal; 467 1.1 christos kev.filter = EVFILT_SIGNAL; 468 1.1 christos kev.flags = EV_ADD; 469 1.1 christos 470 1.1 christos /* Be ready for the signal if it is sent any 471 1.1 christos * time between now and the next call to 472 1.1 christos * kq_dispatch. */ 473 1.1 christos if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1) 474 1.1 christos return (-1); 475 1.1 christos 476 1.1 christos /* We can set the handler for most signals to SIG_IGN and 477 1.1 christos * still have them reported to us in the queue. However, 478 1.1 christos * if the handler for SIGCHLD is SIG_IGN, the system reaps 479 1.1 christos * zombie processes for us, and we don't get any notification. 480 1.1 christos * This appears to be the only signal with this quirk. */ 481 1.1 christos if (evsig_set_handler_(base, nsignal, 482 1.1 christos nsignal == SIGCHLD ? SIG_DFL : SIG_IGN) == -1) 483 1.1 christos return (-1); 484 1.1 christos 485 1.1 christos return (0); 486 1.1 christos } 487 1.1 christos 488 1.1 christos static int 489 1.1 christos kq_sig_del(struct event_base *base, int nsignal, short old, short events, void *p) 490 1.1 christos { 491 1.1 christos struct kqop *kqop = base->evbase; 492 1.1 christos struct kevent kev; 493 1.1 christos 494 1.1 christos struct timespec timeout = { 0, 0 }; 495 1.1 christos (void)p; 496 1.1 christos 497 1.1 christos EVUTIL_ASSERT(nsignal >= 0 && nsignal < NSIG); 498 1.1 christos 499 1.1 christos memset(&kev, 0, sizeof(kev)); 500 1.1 christos kev.ident = nsignal; 501 1.1 christos kev.filter = EVFILT_SIGNAL; 502 1.1 christos kev.flags = EV_DELETE; 503 1.1 christos 504 1.1 christos /* Because we insert signal events 505 1.1 christos * immediately, we need to delete them 506 1.1 christos * immediately, too */ 507 1.1 christos if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1) 508 1.1 christos return (-1); 509 1.1 christos 510 1.1 christos if (evsig_restore_handler_(base, nsignal) == -1) 511 1.1 christos return (-1); 512 1.1 christos 513 1.1 christos return (0); 514 1.1 christos } 515 1.1 christos 516 1.1 christos 517 1.1 christos /* OSX 10.6 and FreeBSD 8.1 add support for EVFILT_USER, which we can use 518 1.1 christos * to wake up the event loop from another thread. */ 519 1.1 christos 520 1.1 christos /* Magic number we use for our filter ID. */ 521 1.1 christos #define NOTIFY_IDENT 42 522 1.1 christos 523 1.1 christos int 524 1.1 christos event_kq_add_notify_event_(struct event_base *base) 525 1.1 christos { 526 1.1 christos struct kqop *kqop = base->evbase; 527 1.1 christos #if defined(EVFILT_USER) && defined(NOTE_TRIGGER) 528 1.1 christos struct kevent kev; 529 1.1 christos struct timespec timeout = { 0, 0 }; 530 1.1 christos #endif 531 1.1 christos 532 1.1 christos if (kqop->notify_event_added) 533 1.1 christos return 0; 534 1.1 christos 535 1.1 christos #if defined(EVFILT_USER) && defined(NOTE_TRIGGER) 536 1.1 christos memset(&kev, 0, sizeof(kev)); 537 1.1 christos kev.ident = NOTIFY_IDENT; 538 1.1 christos kev.filter = EVFILT_USER; 539 1.1 christos kev.flags = EV_ADD | EV_CLEAR; 540 1.1 christos 541 1.1 christos if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1) { 542 1.1 christos event_warn("kevent: adding EVFILT_USER event"); 543 1.1 christos return -1; 544 1.1 christos } 545 1.1 christos 546 1.1 christos kqop->notify_event_added = 1; 547 1.1 christos 548 1.1 christos return 0; 549 1.1 christos #else 550 1.1 christos return -1; 551 1.1 christos #endif 552 1.1 christos } 553 1.1 christos 554 1.1 christos int 555 1.1 christos event_kq_notify_base_(struct event_base *base) 556 1.1 christos { 557 1.1 christos struct kqop *kqop = base->evbase; 558 1.1 christos #if defined(EVFILT_USER) && defined(NOTE_TRIGGER) 559 1.1 christos struct kevent kev; 560 1.1 christos struct timespec timeout = { 0, 0 }; 561 1.1 christos #endif 562 1.1 christos if (! kqop->notify_event_added) 563 1.1 christos return -1; 564 1.1 christos 565 1.1 christos #if defined(EVFILT_USER) && defined(NOTE_TRIGGER) 566 1.1 christos memset(&kev, 0, sizeof(kev)); 567 1.1 christos kev.ident = NOTIFY_IDENT; 568 1.1 christos kev.filter = EVFILT_USER; 569 1.1 christos kev.fflags = NOTE_TRIGGER; 570 1.1 christos 571 1.1 christos if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1) { 572 1.1 christos event_warn("kevent: triggering EVFILT_USER event"); 573 1.1 christos return -1; 574 1.1 christos } 575 1.1 christos 576 1.1 christos return 0; 577 1.1 christos #else 578 1.1 christos return -1; 579 1.1 christos #endif 580 1.1 christos } 581 1.1 christos 582 1.1 christos #endif /* EVENT__HAVE_KQUEUE */ 583