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:
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)))
devpoll_del,
devpoll_dispatch,
devpoll_dealloc,
- 1 /* need reinit */
+ 1, /* need reinit */
+ EV_FEATURE_FDS|EV_FEATURE_O1,
};
#define NEVENT 32000
epoll_del,
epoll_dispatch,
epoll_dealloc,
- 1 /* need reinit */
+ 1, /* need reinit */
+ EV_FEATURE_ET|EV_FEATURE_O1,
};
#ifdef HAVE_SETFD
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 {
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> */
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 *
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) {
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 */
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 */
mm_free(methods);
methods = tmp;
-
+
return (methods);
}
return (NULL);
TAILQ_INIT(&cfg->entries);
-
+ cfg->require_features = 0;
+
return (cfg);
}
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)
{
*/
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.
*/
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.
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);
kq_del,
kq_dispatch,
kq_dealloc,
- 1 /* need reinit */
+ 1 /* need reinit */,
+ EV_FEATURE_ET|EV_FEATURE_O1|EV_FEATURE_FDS,
};
static void *
poll_del,
poll_dispatch,
poll_dealloc,
- 0
+ 0, /* doesn't need_reinit */
+ EV_FEATURE_FDS,
};
static void *
select_del,
select_dispatch,
select_dealloc,
- 0
+ 0, /* doesn't need reinit. */
+ EV_FEATURE_FDS,
};
static int select_resize(struct selectop *sop, int fdsz);