return (gettimeofday(tp, NULL));
}
+/* glue stuff */
+
+static int
+event_is_active(struct event_head *ev)
+{
+ return (ev->ev_flags & EVLIST_ACTIVE);
+}
+
+static int
+event_active_events(struct event_head *ev)
+{
+ return (ev->ev_res);
+}
+
+static void
+event_head_set(struct event_head *ev,
+ void (*cb)(struct event_base *, struct event_head *, int, void *),
+ void *cb_arg)
+{
+ ev->ev_pri = 0;
+ ev->ev_res = 0;
+ ev->ev_flags = EVLIST_INIT;
+
+ ev->ev_cb = cb;
+ ev->ev_cb_arg = cb_arg;
+}
+
+static void
+event_make_active(struct event_base *base, struct event_head *ev, int events)
+{
+ if (ev->ev_flags & EVLIST_ACTIVE) {
+ ev->ev_res |= events;
+ return;
+ }
+
+ if (~ev->ev_flags & EVLIST_INTERNAL)
+ base->event_count++;
+ base->event_count_active++;
+
+ TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri], ev, ev_active_next);
+ ev->ev_flags |= EVLIST_ACTIVE;
+ ev->ev_res = events;
+}
+
+static void
+event_remove_active(struct event_base *base, struct event_head *ev)
+{
+ if (!(ev->ev_flags & EVLIST_ACTIVE))
+ event_errx(1, "%s: %p not on active queue", __func__, ev);
+ if (~ev->ev_flags & EVLIST_INTERNAL)
+ base->event_count--;
+ base->event_count_active--;
+
+ TAILQ_REMOVE(base->activequeues[ev->ev_pri], ev, ev_active_next);
+ ev->ev_flags &= ~EVLIST_ACTIVE;
+}
+
+static int
+event_head_priority_set(struct event_base *base,
+ struct event_head *ev, int pri)
+{
+ if (event_is_active(ev))
+ return (-1);
+
+ if (pri < 0 || pri >= base->nactivequeues)
+ return (-1);
+
+ ev->ev_pri = pri;
+
+ return (0);
+}
+
+/* back to normal stuff */
+
struct event_base *
event_init(void)
{
/* Allocate our priority queues */
base->nactivequeues = npriorities;
- base->activequeues = (struct event_list **)event_calloc(
+ base->activequeues = (struct eventhead_list **)event_calloc(
base->nactivequeues,
- npriorities * sizeof(struct event_list *));
+ npriorities * sizeof(struct eventhead_list *));
if (base->activequeues == NULL)
event_err(1, "%s: calloc", __func__);
return (base->event_count > 0);
}
+/*
+ * Traditional libevent events get deleted when they become active
+ * unless they have specifically been set to be persistent.
+ */
+
+static void
+event_legacy_handler(struct event_base *base, struct event *ev,
+ int events, void *arg)
+{
+ short ncalls;
+
+ if (!(ev->ev_events & EV_PERSIST))
+ event_del(ev);
+
+ /* Allows deletes to work */
+ ncalls = ev->ev_ncalls;
+ ev->ev_pncalls = &ncalls;
+ while (ncalls) {
+ ncalls--;
+ ev->ev_ncalls = ncalls;
+ (*ev->ev_callback)((int)ev->ev_fd, events, ev->ev_arg);
+ if (event_gotsig || base->event_break)
+ return;
+ }
+}
+
/*
* Active events are stored in priority queues. Lower priorities are always
* process before higher priorities. Low priority events can starve high
static void
event_process_active(struct event_base *base)
{
- struct event *ev;
- struct event_list *activeq = NULL;
+ struct event_head *ev;
+ struct eventhead_list *activeq = NULL;
int i;
- short ncalls;
for (i = 0; i < base->nactivequeues; ++i) {
if (TAILQ_FIRST(base->activequeues[i]) != NULL) {
assert(activeq != NULL);
for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
- if (ev->ev_events & EV_PERSIST)
- event_queue_remove(base, ev, EVLIST_ACTIVE);
- else
- event_del(ev);
+ event_remove_active(base, ev);
- /* Allows deletes to work */
- ncalls = ev->ev_ncalls;
- ev->ev_pncalls = &ncalls;
- while (ncalls) {
- ncalls--;
- ev->ev_ncalls = ncalls;
- (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
- if (event_gotsig || base->event_break)
- return;
- }
+ (*ev->ev_cb)(base, ev, ev->ev_res, ev->ev_cb_arg);
+ if (event_gotsig || base->event_break)
+ return;
}
}
event_set(struct event *ev, evutil_socket_t fd, short events,
void (*callback)(evutil_socket_t, short, void *), void *arg)
{
+ event_head_set(EVHEAD(ev), EVENT_CB(event_legacy_handler), NULL);
+
/* Take the current base - caller needs to set the real base later */
ev->ev_base = current_base;
+ ev->ev_flags = 0;
ev->ev_callback = callback;
ev->ev_arg = arg;
ev->ev_fd = fd;
ev->ev_events = events;
- ev->ev_res = 0;
- ev->ev_flags = EVLIST_INIT;
ev->ev_ncalls = 0;
ev->ev_pncalls = NULL;
min_heap_elem_init(ev);
/* by default, we put new events into the middle priority */
- if(current_base)
- ev->ev_pri = current_base->nactivequeues/2;
+ if (current_base)
+ event_priority_set(ev, current_base->nactivequeues/2);
}
int
event_base_set(struct event_base *base, struct event *ev)
{
/* Only innocent events may be assigned to a different base */
- if (ev->ev_flags != EVLIST_INIT)
+ if (event_is_active(EVHEAD(ev)) || ev->ev_flags != 0)
return (-1);
ev->ev_base = base;
- ev->ev_pri = base->nactivequeues/2;
+ event_head_priority_set(base, EVHEAD(ev), base->nactivequeues/2);
return (0);
}
int
event_priority_set(struct event *ev, int pri)
{
- if (ev->ev_flags & EVLIST_ACTIVE)
- return (-1);
- if (pri < 0 || pri >= ev->ev_base->nactivequeues)
- return (-1);
-
- ev->ev_pri = pri;
-
- return (0);
+ return (event_head_priority_set(ev->ev_base, EVHEAD(ev), pri));
}
/*
if (ev->ev_flags & EVLIST_INSERTED)
flags |= (ev->ev_events & (EV_READ|EV_WRITE));
- if (ev->ev_flags & EVLIST_ACTIVE)
- flags |= ev->ev_res;
+ if (event_is_active(EVHEAD(ev)))
+ flags |= event_active_events(EVHEAD(ev));
if (ev->ev_flags & EVLIST_TIMEOUT)
flags |= EV_TIMEOUT;
if (ev->ev_flags & EVLIST_SIGNAL)
/* Check if it is active due to a timeout. Rescheduling
* this timeout before the callback can be executed
* removes it from the active list. */
- if ((ev->ev_flags & EVLIST_ACTIVE) &&
- (ev->ev_res & EV_TIMEOUT)) {
+ if (event_is_active(EVHEAD(ev)) &&
+ (event_active_events(EVHEAD(ev)) & EV_TIMEOUT)) {
/* See if we are just active executing this
* event in a loop
*/
*ev->ev_pncalls = 0;
}
- event_queue_remove(base, ev, EVLIST_ACTIVE);
+ event_remove_active(base, EVHEAD(ev));
}
gettime(&now);
event_queue_insert(base, ev, EVLIST_TIMEOUT);
}
- if ((ev->ev_events & (EV_READ|EV_WRITE)) &&
- !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
- event_queue_insert(base, ev, EVLIST_INSERTED);
+ if (ev->ev_events & (EV_READ|EV_WRITE)) {
+ if ((ev->ev_flags & EVLIST_INSERTED) == 0 &&
+ !event_is_active(EVHEAD(ev))) {
+ event_queue_insert(base, ev, EVLIST_INSERTED);
- return (evsel->add(evbase, ev));
+ return (evsel->add(evbase, ev));
+ }
} else if ((ev->ev_events & EV_SIGNAL) &&
!(ev->ev_flags & EVLIST_SIGNAL)) {
event_queue_insert(base, ev, EVLIST_SIGNAL);
if (ev->ev_flags & EVLIST_TIMEOUT)
event_queue_remove(base, ev, EVLIST_TIMEOUT);
- if (ev->ev_flags & EVLIST_ACTIVE)
- event_queue_remove(base, ev, EVLIST_ACTIVE);
+ if (event_is_active(EVHEAD(ev)))
+ event_remove_active(base, EVHEAD(ev));
if (ev->ev_flags & EVLIST_INSERTED) {
event_queue_remove(base, ev, EVLIST_INSERTED);
void
event_active(struct event *ev, int res, short ncalls)
{
- /* We get different kinds of events, add them together */
- if (ev->ev_flags & EVLIST_ACTIVE) {
- ev->ev_res |= res;
+ /* If we get different kinds of events, add them together */
+ int was_active = event_is_active(EVHEAD(ev));
+
+ event_make_active(ev->ev_base, EVHEAD(ev), res);
+
+ if (was_active)
return;
- }
- ev->ev_res = res;
ev->ev_ncalls = ncalls;
ev->ev_pncalls = NULL;
- event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);
}
static int
ev->ev_flags &= ~queue;
switch (queue) {
- case EVLIST_ACTIVE:
- base->event_count_active--;
- TAILQ_REMOVE(base->activequeues[ev->ev_pri],
- ev, ev_active_next);
- break;
case EVLIST_SIGNAL:
TAILQ_REMOVE(&base->sig.signalqueue, ev, ev_signal_next);
break;
void
event_queue_insert(struct event_base *base, struct event *ev, int queue)
{
- if (ev->ev_flags & queue) {
- /* Double insertion is possible for active events */
- if (queue & EVLIST_ACTIVE)
- return;
-
+ if (ev->ev_flags & queue)
event_errx(1, "%s: %p(fd %d) already on queue %x", __func__,
ev, ev->ev_fd, queue);
- }
if (~ev->ev_flags & EVLIST_INTERNAL)
base->event_count++;
ev->ev_flags |= queue;
switch (queue) {
- case EVLIST_ACTIVE:
- base->event_count_active++;
- TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri],
- ev,ev_active_next);
- break;
case EVLIST_SIGNAL:
TAILQ_INSERT_TAIL(&base->sig.signalqueue, ev, ev_signal_next);
break;
/* EVLIST_X_ Private space: 0x1000-0xf000 */
#define EVLIST_ALL (0xf000 | 0x9f)
-#define EV_TIMEOUT 0x01
-#define EV_READ 0x02
-#define EV_WRITE 0x04
-#define EV_SIGNAL 0x08
-#define EV_PERSIST 0x10 /* Persistant event */
+#define EV_TIMEOUT 0x0001
+#define EV_READ 0x0002
+#define EV_WRITE 0x0004
+#define EV_SIGNAL 0x0008
+#define EV_PERSIST 0x0800 /* Persistant event */
/* Fix so that ppl dont have to run with <sys/queue.h> */
#ifndef TAILQ_ENTRY
}
#endif /* !TAILQ_ENTRY */
+#define EVHEAD(x) ((struct event_head *)(x))
+
struct event_base;
+
+/** a structure common to all events
+ *
+ * struct event_head contains elements common to all event types.
+ * it needs to be the first element of any structure that defines
+ * a new event type.
+ */
+struct event_head {
+ TAILQ_ENTRY (event_head) (ev_active_next);
+ int ev_pri; /*!< smaller numbers are higher priority */
+ int ev_res; /*!< result passed to event callback */
+ int ev_flags; /*!< keeps track of initialization and activation */
+
+ void (*ev_cb)(struct event_base *, struct event_head *,
+ int events, void *);
+ void *ev_cb_arg;
+};
+
struct event {
- TAILQ_ENTRY (event) ev_next;
- TAILQ_ENTRY (event) ev_active_next;
+ struct event_head head;
+
+ TAILQ_ENTRY (event) (ev_next);
TAILQ_ENTRY (event) ev_signal_next;
unsigned int min_heap_idx; /* for managing timeouts */
+ int ev_flags;
+
struct event_base *ev_base;
evutil_socket_t ev_fd;
struct timeval ev_timeout;
- int ev_pri; /* smaller numbers are higher priority */
-
void (*ev_callback)(evutil_socket_t, short, void *arg);
void *ev_arg;
-
- int ev_res; /* result passed to event callback */
- int ev_flags;
};
#define EVENT_SIGNAL(ev) (int)(ev)->ev_fd
*/
#define evtimer_del(ev) event_del(ev)
#define evtimer_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv)
-#define evtimer_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
+#define evtimer_initialized(ev) (EVHEAD(ev)->ev_flags & EVLIST_INIT)
/**
* Add a timeout event.
#define timeout_del(ev) event_del(ev)
#define timeout_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv)
-#define timeout_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
+#define timeout_initialized(ev) (EVHEAD(ev)->ev_flags & EVLIST_INIT)
#define signal_add(ev, tv) event_add(ev, tv)
#define signal_set(ev, x, cb, arg) \
event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg)
#define signal_del(ev) event_del(ev)
#define signal_pending(ev, tv) event_pending(ev, EV_SIGNAL, tv)
-#define signal_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
+#define signal_initialized(ev) (EVHEAD(ev)->ev_flags & EVLIST_INIT)
/**
Prepare an event structure to be added.
initialized
*/
#ifdef WIN32
-#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT && (ev)->ev_fd != (int)INVALID_HANDLE_VALUE)
+#define event_initialized(ev) (EVHEAD(ev)->ev_flags & EVLIST_INIT && (ev)->ev_fd != (int)INVALID_HANDLE_VALUE)
#else
-#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
+#define event_initialized(ev) (EVHEAD(ev)->ev_flags & EVLIST_INIT)
#endif