Add new functions to access backends by their features and to query the features...
authorNick Mathewson <nickm@torproject.org>
Sat, 31 May 2008 14:37:31 +0000 (14:37 +0000)
committerNick Mathewson <nickm@torproject.org>
Sat, 31 May 2008 14:37:31 +0000 (14:37 +0000)
svn:r842

ChangeLog
WIN32-Code/win32.c
devpoll.c
epoll.c
event-internal.h
event.c
include/event2/event.h
kqueue.c
poll.c
select.c

index c934f35caa1a8b7f37b50bfb943b6f2eb15a13d0..fabc43daf05bfa70d25eba095869941289a98bae 100644 (file)
--- 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:
index 4050cf176677a239e7f0551ee59c0a628c46bd73..53b3468c6177842fad3a5ada9240f6e65bdc4077 100644 (file)
@@ -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)))
index ccb47c29f5d257dd3f7c4a439d497d0b696fa6da..c40a718d85ff7f1bbbf2795978d9121e58f57270 100644 (file)
--- 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 0b718cc85563032e6b58ec30619217b9b7c2ddb0..d5a75dc23044fa744a418944da8619bd42570094 100644 (file)
--- 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
index 97246ca151cc8d6c25d5b2b800edc38b7dc2e754..a8a2a2c41bffa7aef5c86194032b07001d350746 100644 (file)
@@ -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 <sys/queue.h> */
diff --git a/event.c b/event.c
index da2b6f3dcab5c2627d397769e379d76694a59dff..676dd0861160a1f56e881a0acfd32131aee58dc1 100644 (file)
--- 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)
 {
index 4cd4608ddeae32efd0d360dfe5a4948defec54be..dbc2bbc43644503a88f34594ef465b50e9212c51 100644 (file)
@@ -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:
+   <pre>
+     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);
+     }
+   </pre>
+
+   @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);
index 38278938c376328b0ec554dc50133f1510b4f126..862aa2bcba76e46d94c00f043ff3c28c512ebb7a 100644 (file)
--- 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 7b2270bc1a10c25d182b8e7863c7ffe8fcacfc2d..44570729a5399c64d2554c011179ec379d136a01 100644 (file)
--- 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 *
index 0df99e58606793a21ee5996d46cc41e36e7f0ddb..91ba6abfa81daab07eaa910f0a74a05681e601c2 100644 (file)
--- 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);