tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

kqueue.c (15128B)


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