rollback r594: restructuring to make event activation independent.

changes are going to wait for api design


svn:r612
This commit is contained in:
Niels Provos 2007-12-24 22:49:30 +00:00
parent 68725dc8bd
commit 03589ccb12
4 changed files with 84 additions and 176 deletions

View File

@ -25,7 +25,6 @@ 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
o Correctly handle DNS replies with no answers set (Fixes bug 1846282)
o add -Wstrict-aliasing to warnings and more cleanup
o removed linger from http server socket; reported by Ilya Martynov

View File

@ -57,7 +57,7 @@ struct event_base {
int event_break; /* Set to terminate loop immediately */
/* active event management */
TAILQ_HEAD (eventhead_list, event_head) **activequeues;
struct event_list **activequeues;
int nactivequeues;
/* signal handling info */
@ -69,9 +69,6 @@ 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 <sys/queue.h> */
#ifndef HAVE_TAILQFOREACH
#define TAILQ_FIRST(head) ((head)->tqh_first)

202
event.c
View File

@ -155,80 +155,6 @@ 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)
{
@ -375,9 +301,9 @@ event_base_priority_init(struct event_base *base, int npriorities)
/* Allocate our priority queues */
base->nactivequeues = npriorities;
base->activequeues = (struct eventhead_list **)event_calloc(
base->activequeues = (struct event_list **)event_calloc(
base->nactivequeues,
npriorities * sizeof(struct eventhead_list *));
npriorities * sizeof(struct event_list *));
if (base->activequeues == NULL)
event_err(1, "%s: calloc", __func__);
@ -397,32 +323,6 @@ 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
@ -432,9 +332,10 @@ event_legacy_handler(struct event_base *base, struct event *ev,
static void
event_process_active(struct event_base *base)
{
struct event_head *ev;
struct eventhead_list *activeq = NULL;
struct event *ev;
struct event_list *activeq = NULL;
int i;
short ncalls;
for (i = 0; i < base->nactivequeues; ++i) {
if (TAILQ_FIRST(base->activequeues[i]) != NULL) {
@ -446,11 +347,21 @@ event_process_active(struct event_base *base)
assert(activeq != NULL);
for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
event_remove_active(base, ev);
if (ev->ev_events & EV_PERSIST)
event_queue_remove(base, ev, EVLIST_ACTIVE);
else
event_del(ev);
(*ev->ev_cb)(base, ev, ev->ev_res, ev->ev_cb_arg);
if (event_gotsig || base->event_break)
return;
/* 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;
}
}
}
@ -674,35 +585,34 @@ 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)
event_priority_set(ev, current_base->nactivequeues/2);
if(current_base)
ev->ev_pri = 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 (event_is_active(EVHEAD(ev)) || ev->ev_flags != 0)
if (ev->ev_flags != EVLIST_INIT)
return (-1);
ev->ev_base = base;
event_head_priority_set(base, EVHEAD(ev), base->nactivequeues/2);
ev->ev_pri = base->nactivequeues/2;
return (0);
}
@ -715,7 +625,14 @@ event_base_set(struct event_base *base, struct event *ev)
int
event_priority_set(struct event *ev, int pri)
{
return (event_head_priority_set(ev->ev_base, EVHEAD(ev), 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);
}
/*
@ -730,8 +647,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 (event_is_active(EVHEAD(ev)))
flags |= event_active_events(EVHEAD(ev));
if (ev->ev_flags & EVLIST_ACTIVE)
flags |= ev->ev_res;
if (ev->ev_flags & EVLIST_TIMEOUT)
flags |= EV_TIMEOUT;
if (ev->ev_flags & EVLIST_SIGNAL)
@ -780,8 +697,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 (event_is_active(EVHEAD(ev)) &&
(event_active_events(EVHEAD(ev)) & EV_TIMEOUT)) {
if ((ev->ev_flags & EVLIST_ACTIVE) &&
(ev->ev_res & EV_TIMEOUT)) {
/* See if we are just active executing this
* event in a loop
*/
@ -790,7 +707,7 @@ event_add(struct event *ev, struct timeval *tv)
*ev->ev_pncalls = 0;
}
event_remove_active(base, EVHEAD(ev));
event_queue_remove(base, ev, EVLIST_ACTIVE);
}
gettime(&now);
@ -803,13 +720,11 @@ event_add(struct event *ev, struct timeval *tv)
event_queue_insert(base, ev, EVLIST_TIMEOUT);
}
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);
if ((ev->ev_events & (EV_READ|EV_WRITE)) &&
!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
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);
@ -849,8 +764,8 @@ event_del(struct event *ev)
if (ev->ev_flags & EVLIST_TIMEOUT)
event_queue_remove(base, ev, EVLIST_TIMEOUT);
if (event_is_active(EVHEAD(ev)))
event_remove_active(base, EVHEAD(ev));
if (ev->ev_flags & EVLIST_ACTIVE)
event_queue_remove(base, ev, EVLIST_ACTIVE);
if (ev->ev_flags & EVLIST_INSERTED) {
event_queue_remove(base, ev, EVLIST_INSERTED);
@ -866,16 +781,16 @@ event_del(struct event *ev)
void
event_active(struct event *ev, int res, short ncalls)
{
/* 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)
/* We get different kinds of events, add them together */
if (ev->ev_flags & EVLIST_ACTIVE) {
ev->ev_res |= res;
return;
}
ev->ev_res = res;
ev->ev_ncalls = ncalls;
ev->ev_pncalls = NULL;
event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);
}
static int
@ -983,6 +898,11 @@ 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;
@ -1000,15 +920,25 @@ 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)
if (ev->ev_flags & queue) {
/* Double insertion is possible for active events */
if (queue & EVLIST_ACTIVE)
return;
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;

52
event.h
View File

@ -192,11 +192,11 @@ typedef unsigned short u_short;
/* EVLIST_X_ Private space: 0x1000-0xf000 */
#define EVLIST_ALL (0xf000 | 0x9f)
#define EV_TIMEOUT 0x0001
#define EV_READ 0x0002
#define EV_WRITE 0x0004
#define EV_SIGNAL 0x0008
#define EV_PERSIST 0x0800 /* Persistant event */
#define EV_TIMEOUT 0x01
#define EV_READ 0x02
#define EV_WRITE 0x04
#define EV_SIGNAL 0x08
#define EV_PERSIST 0x10 /* Persistant event */
/* Fix so that ppl dont have to run with <sys/queue.h> */
#ifndef TAILQ_ENTRY
@ -208,36 +208,13 @@ 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 {
struct event_head head;
TAILQ_ENTRY (event) (ev_next);
TAILQ_ENTRY (event) ev_next;
TAILQ_ENTRY (event) ev_active_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;
@ -247,8 +224,13 @@ 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
@ -482,7 +464,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) (EVHEAD(ev)->ev_flags & EVLIST_INIT)
#define evtimer_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
/**
* Add a timeout event.
@ -511,14 +493,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) (EVHEAD(ev)->ev_flags & EVLIST_INIT)
#define timeout_initialized(ev) ((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) (EVHEAD(ev)->ev_flags & EVLIST_INIT)
#define signal_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
/**
Prepare an event structure to be added.
@ -659,9 +641,9 @@ int event_pending(struct event *, short, struct timeval *);
initialized
*/
#ifdef WIN32
#define event_initialized(ev) (EVHEAD(ev)->ev_flags & EVLIST_INIT && (ev)->ev_fd != (int)INVALID_HANDLE_VALUE)
#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT && (ev)->ev_fd != (int)INVALID_HANDLE_VALUE)
#else
#define event_initialized(ev) (EVHEAD(ev)->ev_flags & EVLIST_INIT)
#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
#endif