From 7aa845b73b93f84bf46276bb5669ee0cb5e81b6c Mon Sep 17 00:00:00 2001 From: Niels Provos Date: Sun, 16 Dec 2007 04:10:30 +0000 Subject: [PATCH] restructure the code to make event activation independent of regular event logic svn:r594 --- ChangeLog | 1 + event-internal.h | 5 +- event.c | 202 +++++++++++++++++++++++++++++++---------------- event.h | 52 ++++++++---- 4 files changed, 176 insertions(+), 84 deletions(-) diff --git a/ChangeLog b/ChangeLog index 60278ece..cd856a19 100644 --- a/ChangeLog +++ b/ChangeLog @@ -25,6 +25,7 @@ Changes in current version: o pull setters/getters out of RPC structures into a base class to which we just need to store a pointer; this reduces the memory footprint of these structures. o prefix {encode,decode}_tag functions with evtag to avoid collisions o fix a bug with event_rpcgen for integers + o restructure the code to make event activation independent of regular event logic Changes in 1.4.0: diff --git a/event-internal.h b/event-internal.h index f61757c1..c1f4a2dc 100644 --- a/event-internal.h +++ b/event-internal.h @@ -57,7 +57,7 @@ struct event_base { int event_break; /* Set to terminate loop immediately */ /* active event management */ - struct event_list **activequeues; + TAILQ_HEAD (eventhead_list, event_head) **activequeues; int nactivequeues; /* signal handling info */ @@ -69,6 +69,9 @@ struct event_base { struct min_heap timeheap; }; +#define EVENT_CB(x) \ + (void (*)(struct event_base *, struct event_head *, int, void *))(x) + /* Internal use only: Functions that might be missing from */ #ifndef HAVE_TAILQFOREACH #define TAILQ_FIRST(head) ((head)->tqh_first) diff --git a/event.c b/event.c index 9b54cfcc..4c199152 100644 --- a/event.c +++ b/event.c @@ -155,6 +155,80 @@ gettime(struct timeval *tp) 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) { @@ -301,9 +375,9 @@ event_base_priority_init(struct event_base *base, int npriorities) /* 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__); @@ -323,6 +397,32 @@ event_haveevents(struct event_base *base) 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 @@ -332,10 +432,9 @@ event_haveevents(struct event_base *base) 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) { @@ -347,21 +446,11 @@ event_process_active(struct event_base *base) 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; } } @@ -585,34 +674,35 @@ void 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); } @@ -625,14 +715,7 @@ event_base_set(struct event_base *base, struct event *ev) 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)); } /* @@ -647,8 +730,8 @@ event_pending(struct event *ev, short event, struct timeval *tv) 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) @@ -697,8 +780,8 @@ event_add(struct event *ev, struct timeval *tv) /* 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 */ @@ -707,7 +790,7 @@ event_add(struct event *ev, struct timeval *tv) *ev->ev_pncalls = 0; } - event_queue_remove(base, ev, EVLIST_ACTIVE); + event_remove_active(base, EVHEAD(ev)); } gettime(&now); @@ -720,11 +803,13 @@ event_add(struct event *ev, struct timeval *tv) 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); @@ -764,8 +849,8 @@ event_del(struct event *ev) 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); @@ -781,16 +866,16 @@ event_del(struct event *ev) 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 @@ -898,11 +983,6 @@ event_queue_remove(struct event_base *base, struct event *ev, int queue) 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; @@ -920,25 +1000,15 @@ event_queue_remove(struct event_base *base, struct event *ev, int queue) 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; diff --git a/event.h b/event.h index 86474dfc..c0bd8aca 100644 --- a/event.h +++ b/event.h @@ -192,11 +192,11 @@ typedef unsigned short u_short; /* 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 */ #ifndef TAILQ_ENTRY @@ -208,13 +208,36 @@ struct { \ } #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; @@ -224,13 +247,8 @@ struct event { 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 @@ -464,7 +482,7 @@ int event_base_loopbreak(struct event_base *); */ #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. @@ -493,14 +511,14 @@ int event_base_loopbreak(struct event_base *); #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. @@ -641,9 +659,9 @@ int event_pending(struct event *, short, struct timeval *); 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 -- 2.40.0