diff options
author | Nick Mathewson <nickm@torproject.org> | 2010-09-17 00:34:13 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2012-04-11 16:14:09 -0400 |
commit | 53a07fe2f95c360d060b9fd58dfcd929c2c1aac2 (patch) | |
tree | 21cf5783d3b08b6c016815f6390a9c04b06f77a4 /kqueue.c | |
parent | 9bf866f5d14b1cdc6f56eccb1dc0ecb9c70f2c21 (diff) | |
download | libevent-53a07fe2f95c360d060b9fd58dfcd929c2c1aac2.tar.gz |
Replace pipe-based notification with EVFILT_USER where possible
Sufficiently recent kqueue implementations have an EVFILT_USER filter
that we can use to wake up an event base from another thread. When
it's supported, we now use this mechanism rather than our old
(pipe-based) mechanism. This should save some time and complications
on newer OSX and freebsds.
Diffstat (limited to 'kqueue.c')
-rw-r--r-- | kqueue.c | 73 |
1 files changed, 73 insertions, 0 deletions
@@ -65,6 +65,8 @@ #include "evthread-internal.h" #include "changelist-internal.h" +#include "kqueue-internal.h" + #define NEVENT 64 struct kqop { @@ -74,6 +76,7 @@ struct kqop { struct kevent *events; int events_size; int kq; + int notify_event_added; pid_t pid; }; @@ -369,6 +372,10 @@ kq_dispatch(struct event_base *base, struct timeval *tv) which |= EV_WRITE; } else if (events[i].filter == EVFILT_SIGNAL) { which |= EV_SIGNAL; +#ifdef EVFILT_USER + } else if (events[i].filter == EVFILT_USER) { + base->is_notify_pending = 0; +#endif } if (!which) @@ -473,4 +480,70 @@ kq_sig_del(struct event_base *base, int nsignal, short old, short events, void * return (0); } + +/* OSX 10.6 and FreeBSD 8.1 add support for EVFILT_USER, which we can use + * to wake up the event loop from another thread. */ + +/* Magic number we use for our filter ID. */ +#define NOTIFY_IDENT 42 + +int +event_kq_add_notify_event_(struct event_base *base) +{ + struct kqop *kqop = base->evbase; +#if defined(EVFILT_USER) && defined(NOTE_TRIGGER) + struct kevent kev; + struct timespec timeout = { 0, 0 }; +#endif + + if (kqop->notify_event_added) + return 0; + +#if defined(EVFILT_USER) && defined(NOTE_TRIGGER) + memset(&kev, 0, sizeof(kev)); + kev.ident = NOTIFY_IDENT; + kev.filter = EVFILT_USER; + kev.flags = EV_ADD | EV_CLEAR; + + if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1) { + event_warn("kevent: adding EVFILT_USER event"); + return -1; + } + + kqop->notify_event_added = 1; + + return 0; +#else + return -1; +#endif +} + +int +event_kq_notify_base_(struct event_base *base) +{ + struct kqop *kqop = base->evbase; +#if defined(EVFILT_USER) && defined(NOTE_TRIGGER) + struct kevent kev; + struct timespec timeout = { 0, 0 }; +#endif + if (! kqop->notify_event_added) + return -1; + +#if defined(EVFILT_USER) && defined(NOTE_TRIGGER) + memset(&kev, 0, sizeof(kev)); + kev.ident = NOTIFY_IDENT; + kev.filter = EVFILT_USER; + kev.fflags = NOTE_TRIGGER; + + if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1) { + event_warn("kevent: triggering EVFILT_USER event"); + return -1; + } + + return 0; +#else + return -1; +#endif +} + #endif /* EVENT__HAVE_KQUEUE */ |