From 05965921ab76880bf1faf3e405ca6c40c32fdf30 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sat, 31 May 2008 14:37:31 +0000 Subject: [PATCH] Add new functions to access backends by their features and to query the features of a backend. svn:r842 --- ChangeLog | 2 ++ WIN32-Code/win32.c | 3 ++- devpoll.c | 3 ++- epoll.c | 3 ++- event-internal.h | 3 +++ event.c | 41 ++++++++++++++++++++++++++++++-------- include/event2/event.h | 45 +++++++++++++++++++++++++++++++++++++++++- kqueue.c | 3 ++- poll.c | 3 ++- select.c | 3 ++- 10 files changed, 94 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index c934f35c..fabc43da 100644 --- a/ChangeLog +++ b/ChangeLog @@ -104,6 +104,8 @@ Changes in current version: o constify struct timeval * where possible o make event_get_supported_methods obey environment variables o support for edge-triggered events on epoll and kqueue backends: patch from Valery Kholodkov + o support for selecting event backends by their features, and for querying the features of a backend. + o change failing behavior of event_base_new_with_config: if a config is provided and no backend is selected, return NULL instead of aborting. Changes in 1.4.0: diff --git a/WIN32-Code/win32.c b/WIN32-Code/win32.c index 4050cf17..53b3468c 100644 --- a/WIN32-Code/win32.c +++ b/WIN32-Code/win32.c @@ -120,7 +120,8 @@ struct eventop win32ops = { win32_del, win32_dispatch, win32_dealloc, - 0 + 0, /* doesn't need reinit */ + 0, /* No features supported. */ }; #define FD_SET_ALLOC_SIZE(n) ((sizeof(struct win_fd_set) + ((n)-1)*sizeof(SOCKET))) diff --git a/devpoll.c b/devpoll.c index ccb47c29..c40a718d 100644 --- a/devpoll.c +++ b/devpoll.c @@ -83,7 +83,8 @@ struct eventop devpollops = { devpoll_del, devpoll_dispatch, devpoll_dealloc, - 1 /* need reinit */ + 1, /* need reinit */ + EV_FEATURE_FDS|EV_FEATURE_O1, }; #define NEVENT 32000 diff --git a/epoll.c b/epoll.c index 0b718cc8..d5a75dc2 100644 --- a/epoll.c +++ b/epoll.c @@ -83,7 +83,8 @@ struct eventop epollops = { epoll_del, epoll_dispatch, epoll_dealloc, - 1 /* need reinit */ + 1, /* need reinit */ + EV_FEATURE_ET|EV_FEATURE_O1, }; #ifdef HAVE_SETFD diff --git a/event-internal.h b/event-internal.h index 97246ca1..a8a2a2c4 100644 --- a/event-internal.h +++ b/event-internal.h @@ -55,6 +55,7 @@ struct eventop { void (*dealloc)(struct event_base *, void *); /* set if we need to reinitialize the event base */ int need_reinit; + enum event_method_feature features; }; struct event_base { @@ -103,6 +104,8 @@ struct event_config_entry { struct event_config { TAILQ_HEAD(event_configq, event_config_entry) entries; + + enum event_method_feature require_features; }; /* Internal use only: Functions that might be missing from */ diff --git a/event.c b/event.c index da2b6f3d..676dd086 100644 --- a/event.c +++ b/event.c @@ -219,7 +219,12 @@ event_is_method_disabled(const char *name) for (i = 8; environment[i] != '\0'; ++i) environment[i] = toupper(environment[i]); return (getenv(environment) != NULL); - +} + +enum event_method_feature +event_base_get_features(struct event_base *base) +{ + return base->evsel->features; } struct event_base * @@ -236,13 +241,13 @@ event_base_new_with_config(struct event_config *cfg) detect_monotonic(); gettime(base, &base->event_tv); - + min_heap_ctor(&base->timeheap); TAILQ_INIT(&base->eventqueue); TAILQ_INIT(&base->sig.signalqueue); base->sig.ev_signal_pair[0] = -1; base->sig.ev_signal_pair[1] = -1; - + base->evbase = NULL; for (i = 0; eventops[i] && !base->evbase; i++) { if (cfg != NULL) { @@ -250,6 +255,9 @@ event_base_new_with_config(struct event_config *cfg) if (event_config_is_avoided_method(cfg, eventops[i]->name)) continue; + if ((eventops[i]->features & cfg->require_features) + != cfg->require_features) + continue; } /* also obey the environment variables */ @@ -261,10 +269,16 @@ event_base_new_with_config(struct event_config *cfg) base->evbase = base->evsel->init(base); } - if (base->evbase == NULL) - event_errx(1, "%s: no event mechanism available", __func__); + if (base->evbase == NULL) { + if (cfg == NULL) + event_errx(1, "%s: no event mechanism available", __func__); + else { + event_base_free(base); + return NULL; + } + } - if (getenv("EVENT_SHOW_METHOD")) + if (getenv("EVENT_SHOW_METHOD")) event_msgx("libevent using: %s", base->evsel->name); /* allocate a single active event queue */ @@ -397,7 +411,7 @@ event_get_supported_methods(void) mm_free(methods); methods = tmp; - + return (methods); } @@ -410,7 +424,8 @@ event_config_new(void) return (NULL); TAILQ_INIT(&cfg->entries); - + cfg->require_features = 0; + return (cfg); } @@ -450,6 +465,16 @@ event_config_avoid_method(struct event_config *cfg, const char *method) return (0); } +int +event_config_require_features(struct event_config *cfg, + enum event_method_feature features) +{ + if (!cfg) + return (-1); + cfg->require_features = features; + return (0); +} + int event_priority_init(int npriorities) { diff --git a/include/event2/event.h b/include/event2/event.h index 4cd4608d..dbc2bbc4 100644 --- a/include/event2/event.h +++ b/include/event2/event.h @@ -100,6 +100,11 @@ int event_base_dispatch(struct event_base *); */ const char *event_base_get_method(struct event_base *); +/** + Return a bitmask of the features implemented by an event base. + */ +enum event_method_feature event_base_get_features(struct event_base *base); + /** Gets all event notification mechanisms supported by libevent. @@ -144,6 +149,43 @@ void event_config_free(struct event_config *cfg); */ int event_config_avoid_method(struct event_config *cfg, const char *method); +enum event_method_feature { + /* Require an event method that allows edge-triggered events with EV_ET. */ + EV_FEATURE_ET = 0x01, + /* Require an event method where having one event triggered among + * many is [approximately] an O(1) operation. This excludes (for + * example) select and poll, which are approximately O(N) for N + * equal to the total number of possible events. */ + EV_FEATURE_O1 = 0x02, + /* Require an event method that allows file descriptors as well as + * sockets. */ + EV_FEATURE_FDS = 0x04, +} event_method_feature; + +/** + Enters a required event method feature that the application demands. + + Note that not every feature or combination of features is supported + on every platform. Code that requests features should be prepared + to handle the case where event_base_new_with_config() returns NULL, as in: +
+     event_config_require_features(cfg, EV_FEATURE_ET);
+     base = event_base_new_with_config(cfg);
+     if (base == NULL) {
+       // We can't get edge-triggered behavior here.
+       event_config_require_features(cfg, 0);
+       base = event_base_new_with_config(cfg);
+     }
+   
+ + @param cfg the event configuration object + @param feature a bitfield of one or more event_method_feature values. + Replaces values from previous calls to this function. + @return 0 on success, -1 on failure. +*/ +int event_config_require_features(struct event_config *cfg, + enum event_method_feature feature); + /** Initialize the event API. @@ -152,7 +194,8 @@ int event_config_avoid_method(struct event_config *cfg, const char *method); can currently be used to avoid certain event notification mechanisms. @param cfg the event configuration object - @return an initialized event_base that can be used to registering events. + @return an initialized event_base that can be used to registering events, + or NULL if no event base can be created with the requested event_config. @see event_base_new(), event_base_free(), event_init(), event_assign() */ struct event_base *event_base_new_with_config(struct event_config *cfg); diff --git a/kqueue.c b/kqueue.c index 38278938..862aa2bc 100644 --- a/kqueue.c +++ b/kqueue.c @@ -90,7 +90,8 @@ const struct eventop kqops = { kq_del, kq_dispatch, kq_dealloc, - 1 /* need reinit */ + 1 /* need reinit */, + EV_FEATURE_ET|EV_FEATURE_O1|EV_FEATURE_FDS, }; static void * diff --git a/poll.c b/poll.c index 7b2270bc..44570729 100644 --- a/poll.c +++ b/poll.c @@ -79,7 +79,8 @@ const struct eventop pollops = { poll_del, poll_dispatch, poll_dealloc, - 0 + 0, /* doesn't need_reinit */ + EV_FEATURE_FDS, }; static void * diff --git a/select.c b/select.c index 0df99e58..91ba6abf 100644 --- a/select.c +++ b/select.c @@ -84,7 +84,8 @@ const struct eventop selectops = { select_del, select_dispatch, select_dealloc, - 0 + 0, /* doesn't need reinit. */ + EV_FEATURE_FDS, }; static int select_resize(struct selectop *sop, int fdsz);