--- src/kevent_internal.h | 6 +--- src/source.c | 52 ++------------------------------- src/source_internal.h | 9 ++++- src/source_kevent.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 84 insertions(+), 60 deletions(-) diff --git a/src/kevent_internal.h b/src/kevent_internal.h index 7109439..3ad63c2 100644 --- a/src/kevent_internal.h +++ b/src/kevent_internal.h @@ -28,6 +28,7 @@ #define __DISPATCH_KEVENT_INTERNAL__ #include <internal.h> +#include <sys/event.h> struct dispatch_kevent_s { TAILQ_ENTRY(dispatch_kevent_s) dk_list; @@ -35,11 +36,6 @@ struct dispatch_kevent_s { struct kevent dk_kevent; }; -#define DISPATCH_EVFILT_TIMER (-EVFILT_SYSCOUNT - 1) -#define DISPATCH_EVFILT_CUSTOM_ADD (-EVFILT_SYSCOUNT - 2) -#define DISPATCH_EVFILT_CUSTOM_OR (-EVFILT_SYSCOUNT - 3) -#define DISPATCH_EVFILT_SYSCOUNT (EVFILT_SYSCOUNT + 3) - extern const struct dispatch_source_vtable_s _dispatch_source_kevent_vtable; #if DISPATCH_DEBUG diff --git a/src/source.c b/src/source.c index f2ccd82..01061a4 100644 --- a/src/source.c +++ b/src/source.c @@ -25,8 +25,6 @@ #endif #include <sys/mount.h> -#include "kevent_internal.h" - #ifndef DISPATCH_NO_LEGACY struct dispatch_source_attr_vtable_s { DISPATCH_VTABLE_HEADER(dispatch_source_attr_s); @@ -392,48 +390,17 @@ dispatch_source_create(dispatch_source_type_t type, unsigned long mask, dispatch_queue_t q) { - const struct kevent *proto_kev = &type->ke; dispatch_source_t ds = NULL; - dispatch_kevent_t dk = NULL; // input validation if (type == NULL || (mask & ~type->mask)) { goto out_bad; } - switch (type->ke.filter) { - case EVFILT_SIGNAL: - if (handle >= NSIG) { - goto out_bad; - } - break; - case EVFILT_FS: - case DISPATCH_EVFILT_CUSTOM_ADD: - case DISPATCH_EVFILT_CUSTOM_OR: - case DISPATCH_EVFILT_TIMER: - if (handle) { - goto out_bad; - } - break; - default: - break; - } - ds = calloc(1ul, sizeof(struct dispatch_source_s)); if (slowpath(!ds)) { goto out_bad; } - dk = calloc(1ul, sizeof(struct dispatch_kevent_s)); - if (slowpath(!dk)) { - goto out_bad; - } - - dk->dk_kevent = *proto_kev; - dk->dk_kevent.ident = handle; - dk->dk_kevent.flags |= EV_ADD|EV_ENABLE; - dk->dk_kevent.fflags |= (uint32_t)mask; - dk->dk_kevent.udata = dk; - TAILQ_INIT(&dk->dk_sources); // Initialize as a queue first, then override some settings below. _dispatch_queue_init((dispatch_queue_t)ds); @@ -446,22 +413,10 @@ dispatch_source_create(dispatch_source_type_t type, // do_targetq will be retained below, past point of no-return ds->do_targetq = q; - // Dispatch Source - ds->ds_ident_hack = dk->dk_kevent.ident; - ds->ds_dkev = dk; - ds->ds_pending_data_mask = dk->dk_kevent.fflags; - if ((EV_DISPATCH|EV_ONESHOT) & proto_kev->flags) { - ds->ds_is_level = true; - ds->ds_needs_rearm = true; - } else if (!(EV_CLEAR & proto_kev->flags)) { - // we cheat and use EV_CLEAR to mean a "flag thingy" - ds->ds_is_adder = true; - } - - // Some sources require special processing - if (type->init != NULL) { - type->init(ds, type, handle, mask, q); + if (slowpath (!type->init(ds, type, handle, mask, q))) { + goto out_bad; } + dispatch_assert(!(ds->ds_is_level && ds->ds_is_adder)); #if DISPATCH_DEBUG dispatch_debug(ds, __FUNCTION__); @@ -472,7 +427,6 @@ dispatch_source_create(dispatch_source_type_t type, out_bad: free(ds); - free(dk); return NULL; } diff --git a/src/source_internal.h b/src/source_internal.h index e247e4a..222a85d 100644 --- a/src/source_internal.h +++ b/src/source_internal.h @@ -103,17 +103,22 @@ dispatch_queue_t _dispatch_source_invoke(dispatch_source_t ds); bool _dispatch_source_probe(dispatch_source_t ds); void _dispatch_source_dispose(dispatch_source_t ds); size_t _dispatch_source_debug(dispatch_source_t ds, char* buf, size_t bufsiz); -void _dispatch_source_merge_kevent(dispatch_source_t ds, const struct kevent *ke); void _dispatch_source_kevent_resume(dispatch_source_t ds, uint32_t new_flags, uint32_t del_flags); void _dispatch_kevent_merge(dispatch_source_t ds); void _dispatch_kevent_release(dispatch_source_t ds); void _dispatch_timer_list_update(dispatch_source_t ds); +#ifdef __linux__ +/* In the future, Linux may use epoll or libevent or something like that. + For now, this lets it compile except for the kqueue bits. */ +struct kevent {}; +#endif + struct dispatch_source_type_s { struct kevent ke; uint64_t mask; - void (*init) (dispatch_source_t ds, + bool (*init) (dispatch_source_t ds, dispatch_source_type_t type, uintptr_t handle, unsigned long mask, diff --git a/src/source_kevent.c b/src/source_kevent.c index 2c5a508..0e1d34f 100644 --- a/src/source_kevent.c +++ b/src/source_kevent.c @@ -73,6 +73,7 @@ static struct dispatch_kevent_s _dispatch_kevent_data_add = { .dk_sources = TAILQ_HEAD_INITIALIZER(_dispatch_kevent_data_add.dk_sources), }; +static void _dispatch_source_merge_kevent(dispatch_source_t ds, const struct kevent *ke); static void _dispatch_kevent_resume(dispatch_kevent_t dk, uint32_t new_flags, uint32_t del_flags); #if HAVE_MACH static void _dispatch_kevent_machport_resume(dispatch_kevent_t dk, uint32_t new_flags, uint32_t del_flags); @@ -569,11 +570,63 @@ dispatch_source_merge_data(dispatch_source_t ds, unsigned long val) _dispatch_source_merge_kevent(ds, &kev); } -static void -dispatch_source_type_timer_init(dispatch_source_t ds, dispatch_source_type_t type, uintptr_t handle, unsigned long mask, dispatch_queue_t q) +static bool dispatch_source_type_kevent_init (dispatch_source_t ds, dispatch_source_type_t type, uintptr_t handle, unsigned long mask, dispatch_queue_t q) { + const struct kevent *proto_kev = &type->ke; + dispatch_kevent_t dk = NULL; + + switch (type->ke.filter) { + case EVFILT_SIGNAL: + if (handle >= NSIG) { + return false; + } + break; + case EVFILT_FS: + case DISPATCH_EVFILT_CUSTOM_ADD: + case DISPATCH_EVFILT_CUSTOM_OR: + case DISPATCH_EVFILT_TIMER: + if (handle) { + return false; + } + break; + default: + break; + } + + dk = calloc(1ul, sizeof(struct dispatch_kevent_s)); + if (slowpath(!dk)) { + return false; + } + + dk->dk_kevent = *proto_kev; + dk->dk_kevent.ident = handle; + dk->dk_kevent.flags |= EV_ADD|EV_ENABLE; + dk->dk_kevent.fflags |= (uint32_t)mask; + dk->dk_kevent.udata = dk; + TAILQ_INIT(&dk->dk_sources); + + // Dispatch Source + ds->ds_ident_hack = dk->dk_kevent.ident; + ds->ds_dkev = dk; + ds->ds_pending_data_mask = dk->dk_kevent.fflags; + if ((EV_DISPATCH|EV_ONESHOT) & proto_kev->flags) { + ds->ds_is_level = true; + ds->ds_needs_rearm = true; + } else if (!(EV_CLEAR & proto_kev->flags)) { + // we cheat and use EV_CLEAR to mean a "flag thingy" + ds->ds_is_adder = true; + } + return true; +} + +static bool dispatch_source_type_timer_init (dispatch_source_t ds, dispatch_source_type_t type, uintptr_t handle, unsigned long mask, dispatch_queue_t q) +{ + if (!dispatch_source_type_kevent_init (ds, type, handle, mask, q)) { + return false; + } ds->ds_needs_rearm = true; ds->ds_timer.flags = mask; + return true; } const struct dispatch_source_type_s _dispatch_source_type_timer = { @@ -589,6 +642,7 @@ const struct dispatch_source_type_s _dispatch_source_type_read = { .filter = EVFILT_READ, .flags = EV_DISPATCH, }, + .init = dispatch_source_type_kevent_init }; const struct dispatch_source_type_s _dispatch_source_type_write = { @@ -596,6 +650,7 @@ const struct dispatch_source_type_s _dispatch_source_type_write = { .filter = EVFILT_WRITE, .flags = EV_DISPATCH, }, + .init = dispatch_source_type_kevent_init }; const struct dispatch_source_type_s _dispatch_source_type_proc = { @@ -611,12 +666,14 @@ const struct dispatch_source_type_s _dispatch_source_type_proc = { |NOTE_REAP #endif , + .init = dispatch_source_type_kevent_init }; const struct dispatch_source_type_s _dispatch_source_type_signal = { .ke = { .filter = EVFILT_SIGNAL, }, + .init = dispatch_source_type_kevent_init }; const struct dispatch_source_type_s _dispatch_source_type_vnode = { @@ -630,6 +687,7 @@ const struct dispatch_source_type_s _dispatch_source_type_vnode = { |NOTE_NONE #endif , + .init = dispatch_source_type_kevent_init }; const struct dispatch_source_type_s _dispatch_source_type_vfs = { @@ -646,17 +704,22 @@ const struct dispatch_source_type_s _dispatch_source_type_vfs = { |VQ_VERYLOWDISK #endif , + .init = dispatch_source_type_kevent_init }; #if HAVE_MACH -static void +static bool dispatch_source_type_mach_send_init(dispatch_source_t ds, dispatch_source_type_t type, uintptr_t handle, unsigned long mask, dispatch_queue_t q) { static dispatch_once_t pred; + if (!dispatch_source_type_kevent_init (ds, type, handle, mask, q)) { + return false; + } ds->ds_is_level = false; dispatch_once_f(&pred, NULL, _dispatch_mach_notify_source_init); + return true; } const struct dispatch_source_type_s _dispatch_source_type_mach_send = { @@ -669,10 +732,14 @@ const struct dispatch_source_type_s _dispatch_source_type_mach_send = { .init = dispatch_source_type_mach_send_init, }; -static void +static bool dispatch_source_type_mach_recv_init(dispatch_source_t ds, dispatch_source_type_t type, uintptr_t handle, unsigned long mask, dispatch_queue_t q) { + if (!dispatch_source_type_kevent_init (ds, type, handle, mask, q)) { + return false; + } ds->ds_is_level = false; + return true; } const struct dispatch_source_type_s _dispatch_source_type_mach_recv = { @@ -689,6 +756,7 @@ const struct dispatch_source_type_s _dispatch_source_type_data_add = { .ke = { .filter = DISPATCH_EVFILT_CUSTOM_ADD, }, + .init = dispatch_source_type_kevent_init, }; const struct dispatch_source_type_s _dispatch_source_type_data_or = { @@ -697,6 +765,7 @@ const struct dispatch_source_type_s _dispatch_source_type_data_or = { .flags = EV_CLEAR, .fflags = ~0, }, + .init = dispatch_source_type_kevent_init }; // Updates the ordered list of timers based on next fire date for changes to ds. -- 1.6.2.5