#endif
#include "event.h"
+#include "event-internal.h"
#ifdef HAVE_SELECT
extern const struct eventop selectops;
};
/* Global state */
+struct event_list signalqueue;
-const struct eventop *evsel;
-void *evbase;
-static int event_count; /* counts number of total events */
-static int event_count_active; /* counts number of active events */
-
-/* Handle signals - This is a deprecated interface */
-int (*event_sigcb)(void); /* Signal callback when gotsig is set */
-int event_gotsig; /* Set in signal handler */
-int event_gotterm; /* Set to terminate loop */
+struct event_base *current_base = NULL;
/* Prototypes */
-void event_queue_insert(struct event *, int);
-void event_queue_remove(struct event *, int);
-int event_haveevents(void);
+static void event_queue_insert(struct event_base *, struct event *, int);
+static void event_queue_remove(struct event_base *, struct event *, int);
+static int event_haveevents(struct event_base *);
-static void event_process_active(void);
+static void event_process_active(struct event_base *);
-static RB_HEAD(event_tree, event) timetree;
-
-/* active event management */
-static struct event_list **activequeues;
-static int nactivequeues;
-
-struct event_list signalqueue;
-struct event_list eventqueue;
-static struct timeval event_tv;
+static int timeout_next(struct event_base *, struct timeval *);
+static void timeout_process(struct event_base *);
+static void timeout_correct(struct event_base *, struct timeval *);
static int
compare(struct event *a, struct event *b)
RB_GENERATE(event_tree, event, ev_timeout_node, compare);
-void
+void *
event_init(void)
{
int i;
- event_sigcb = NULL;
- event_gotsig = 0;
- gettimeofday(&event_tv, NULL);
+ if ((current_base = calloc(1, sizeof(struct event_base))) == NULL)
+ err(1, "%s: calloc");
+
+ current_base->event_sigcb = NULL;
+ current_base->event_gotsig = 0;
+ gettimeofday(¤t_base->event_tv, NULL);
#if defined(USE_LOG) && defined(USE_DEBUG)
log_to(stderr);
log_debug_cmd(LOG_MISC, 80);
#endif
- RB_INIT(&timetree);
- TAILQ_INIT(&eventqueue);
+ RB_INIT(¤t_base->timetree);
+ TAILQ_INIT(¤t_base->eventqueue);
TAILQ_INIT(&signalqueue);
- evbase = NULL;
- for (i = 0; eventops[i] && !evbase; i++) {
- evsel = eventops[i];
+ current_base->evbase = NULL;
+ for (i = 0; eventops[i] && !current_base->evbase; i++) {
+ current_base->evsel = eventops[i];
- evbase = evsel->init();
+ current_base->evbase = current_base->evsel->init();
}
- if (evbase == NULL)
+ if (current_base->evbase == NULL)
errx(1, "%s: no event mechanism available", __func__);
if (getenv("EVENT_SHOW_METHOD"))
- fprintf(stderr, "libevent using: %s\n", evsel->name);
+ fprintf(stderr, "libevent using: %s\n",
+ current_base->evsel->name);
/* allocate a single active event queue */
- event_priority_init(1);
+ event_priority_init(current_base, 1);
+
+ return (current_base);
}
int
-event_priority_init(int npriorities)
+event_priority_init(struct event_base *base, int npriorities)
{
int i;
- if (event_count_active)
+ if (base->event_count_active)
return (-1);
- if (nactivequeues && npriorities != nactivequeues) {
- for (i = 0; i < nactivequeues; ++i) {
- free(activequeues[i]);
+ if (base->nactivequeues && npriorities != base->nactivequeues) {
+ for (i = 0; i < base->nactivequeues; ++i) {
+ free(base->activequeues[i]);
}
- free(activequeues);
+ free(base->activequeues);
}
/* Allocate our priority queues */
- nactivequeues = npriorities;
- activequeues = (struct event_list **)calloc(nactivequeues,
+ base->nactivequeues = npriorities;
+ base->activequeues = (struct event_list **)calloc(base->nactivequeues,
npriorities * sizeof(struct event_list *));
- if (activequeues == NULL)
+ if (base->activequeues == NULL)
err(1, "%s: calloc", __func__);
- for (i = 0; i < nactivequeues; ++i) {
- activequeues[i] = malloc(sizeof(struct event_list));
- if (activequeues[i] == NULL)
+ for (i = 0; i < base->nactivequeues; ++i) {
+ base->activequeues[i] = malloc(sizeof(struct event_list));
+ if (base->activequeues[i] == NULL)
err(1, "%s: malloc", __func__);
- TAILQ_INIT(activequeues[i]);
+ TAILQ_INIT(base->activequeues[i]);
}
return (0);
}
int
-event_haveevents(void)
+event_haveevents(struct event_base *base)
{
- return (event_count > 0);
+ return (base->event_count > 0);
}
/*
*/
static void
-event_process_active(void)
+event_process_active(struct event_base *base)
{
struct event *ev;
struct event_list *activeq = NULL;
int i;
short ncalls;
- if (!event_count_active)
+ if (!base->event_count_active)
return;
- for (i = 0; i < nactivequeues; ++i) {
- if (TAILQ_FIRST(activequeues[i]) != NULL) {
- activeq = activequeues[i];
+ for (i = 0; i < base->nactivequeues; ++i) {
+ if (TAILQ_FIRST(base->activequeues[i]) != NULL) {
+ activeq = base->activequeues[i];
break;
}
}
for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
- event_queue_remove(ev, EVLIST_ACTIVE);
+ event_queue_remove(base, ev, EVLIST_ACTIVE);
/* Allows deletes to work */
ncalls = ev->ev_ncalls;
static void
event_loopexit_cb(int fd, short what, void *arg)
{
- event_gotterm = 1;
+ struct event_base *base = arg;
+ base->event_gotterm = 1;
}
+/* not thread safe */
+
int
event_loopexit(struct timeval *tv)
{
- return (event_once(-1, EV_TIMEOUT, event_loopexit_cb, NULL, tv));
+ return (event_once(-1, EV_TIMEOUT, event_loopexit_cb,
+ current_base, tv));
}
+/* not thread safe */
+
int
event_loop(int flags)
{
+ return event_loop_base(current_base, flags);
+}
+
+int
+event_loop_base(struct event_base *base, int flags)
+{
+ const struct eventop *evsel = base->evsel;
+ void *evbase = base->evbase;
struct timeval tv;
int res, done;
/* Calculate the initial events that we are waiting for */
- if (evsel->recalc(evbase, 0) == -1)
+ if (evsel->recalc(base, evbase, 0) == -1)
return (-1);
done = 0;
while (!done) {
/* Terminate the loop if we have been asked to */
- if (event_gotterm) {
- event_gotterm = 0;
+ if (base->event_gotterm) {
+ base->event_gotterm = 0;
break;
}
- while (event_gotsig) {
- event_gotsig = 0;
- if (event_sigcb) {
- res = (*event_sigcb)();
+ while (base->event_gotsig) {
+ base->event_gotsig = 0;
+ if (base->event_sigcb) {
+ res = (*base->event_sigcb)();
if (res == -1) {
errno = EINTR;
return (-1);
/* Check if time is running backwards */
gettimeofday(&tv, NULL);
- if (timercmp(&tv, &event_tv, <)) {
+ if (timercmp(&tv, &base->event_tv, <)) {
struct timeval off;
LOG_DBG((LOG_MISC, 10,
"%s: time is running backwards, corrected",
__func__));
- timersub(&event_tv, &tv, &off);
- timeout_correct(&off);
+ timersub(&base->event_tv, &tv, &off);
+ timeout_correct(base, &off);
}
- event_tv = tv;
+ base->event_tv = tv;
- if (!event_count_active && !(flags & EVLOOP_NONBLOCK))
- timeout_next(&tv);
+ if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK))
+ timeout_next(base, &tv);
else
timerclear(&tv);
/* If we have no events, we just exit */
- if (!event_haveevents())
+ if (!event_haveevents(base))
return (1);
- res = evsel->dispatch(evbase, &tv);
+ res = evsel->dispatch(base, evbase, &tv);
if (res == -1)
return (-1);
- timeout_process();
+ timeout_process(base);
- if (event_count_active) {
- event_process_active();
- if (!event_count_active && (flags & EVLOOP_ONCE))
+ if (base->event_count_active) {
+ event_process_active(base);
+ if (!base->event_count_active && (flags & EVLOOP_ONCE))
done = 1;
} else if (flags & EVLOOP_NONBLOCK)
done = 1;
- if (evsel->recalc(evbase, 0) == -1)
+ if (evsel->recalc(base, evbase, 0) == -1)
return (-1);
}
event_set(struct event *ev, int fd, short events,
void (*callback)(int, short, void *), void *arg)
{
+ /* Take the current base - caller needs to set the real base later */
+ ev->ev_base = current_base;
+
ev->ev_callback = callback;
ev->ev_arg = arg;
#ifdef WIN32
ev->ev_pncalls = NULL;
/* by default, we put new events into the middle priority */
- ev->ev_pri = nactivequeues/2;
+ 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 (ev->ev_flags != EVLIST_INIT)
+ return (-1);
+
+ ev->ev_base = base;
+ ev->ev_pri = current_base->nactivequeues/2;
+
+ return (0);
}
/*
{
if (ev->ev_flags & EVLIST_ACTIVE)
return (-1);
- if (pri < 0 || pri >= nactivequeues)
+ if (pri < 0 || pri >= ev->ev_base->nactivequeues)
return (-1);
ev->ev_pri = pri;
int
event_add(struct event *ev, struct timeval *tv)
{
+ struct event_base *base = ev->ev_base;
+ const struct eventop *evsel = base->evsel;
+ void *evbase = base->evbase;
+
LOG_DBG((LOG_MISC, 55,
"event_add: event: %p, %s%s%scall %p",
ev,
struct timeval now;
if (ev->ev_flags & EVLIST_TIMEOUT)
- event_queue_remove(ev, EVLIST_TIMEOUT);
+ event_queue_remove(base, ev, EVLIST_TIMEOUT);
/* Check if it is active due to a timeout. Rescheduling
* this timeout before the callback can be executed
*ev->ev_pncalls = 0;
}
- event_queue_remove(ev, EVLIST_ACTIVE);
+ event_queue_remove(base, ev, EVLIST_ACTIVE);
}
gettimeofday(&now, NULL);
"event_add: timeout in %d seconds, call %p",
tv->tv_sec, ev->ev_callback));
- event_queue_insert(ev, EVLIST_TIMEOUT);
+ 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(ev, EVLIST_INSERTED);
+ event_queue_insert(base, ev, EVLIST_INSERTED);
return (evsel->add(evbase, ev));
} else if ((ev->ev_events & EV_SIGNAL) &&
!(ev->ev_flags & EVLIST_SIGNAL)) {
- event_queue_insert(ev, EVLIST_SIGNAL);
+ event_queue_insert(base, ev, EVLIST_SIGNAL);
return (evsel->add(evbase, ev));
}
int
event_del(struct event *ev)
{
+ struct event_base *base = ev->ev_base;
+ const struct eventop *evsel = base->evsel;
+ void *evbase = base->evbase;
+
LOG_DBG((LOG_MISC, 80, "event_del: %p, callback %p",
ev, ev->ev_callback));
}
if (ev->ev_flags & EVLIST_TIMEOUT)
- event_queue_remove(ev, EVLIST_TIMEOUT);
+ event_queue_remove(base, ev, EVLIST_TIMEOUT);
if (ev->ev_flags & EVLIST_ACTIVE)
- event_queue_remove(ev, EVLIST_ACTIVE);
+ event_queue_remove(base, ev, EVLIST_ACTIVE);
if (ev->ev_flags & EVLIST_INSERTED) {
- event_queue_remove(ev, EVLIST_INSERTED);
+ event_queue_remove(base, ev, EVLIST_INSERTED);
return (evsel->del(evbase, ev));
} else if (ev->ev_flags & EVLIST_SIGNAL) {
- event_queue_remove(ev, EVLIST_SIGNAL);
+ event_queue_remove(base, ev, EVLIST_SIGNAL);
return (evsel->del(evbase, ev));
}
ev->ev_res = res;
ev->ev_ncalls = ncalls;
ev->ev_pncalls = NULL;
- event_queue_insert(ev, EVLIST_ACTIVE);
+ event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);
}
int
-timeout_next(struct timeval *tv)
+timeout_next(struct event_base *base, struct timeval *tv)
{
struct timeval dflt = TIMEOUT_DEFAULT;
struct timeval now;
struct event *ev;
- if ((ev = RB_MIN(event_tree, &timetree)) == NULL) {
+ if ((ev = RB_MIN(event_tree, &base->timetree)) == NULL) {
*tv = dflt;
return (0);
}
return (0);
}
-void
-timeout_correct(struct timeval *off)
+static void
+timeout_correct(struct event_base *base, struct timeval *off)
{
struct event *ev;
* We can modify the key element of the node without destroying
* the key, beause we apply it to all in the right order.
*/
- RB_FOREACH(ev, event_tree, &timetree)
+ RB_FOREACH(ev, event_tree, &base->timetree)
timersub(&ev->ev_timeout, off, &ev->ev_timeout);
}
void
-timeout_process(void)
+timeout_process(struct event_base *base)
{
struct timeval now;
struct event *ev, *next;
gettimeofday(&now, NULL);
- for (ev = RB_MIN(event_tree, &timetree); ev; ev = next) {
+ for (ev = RB_MIN(event_tree, &base->timetree); ev; ev = next) {
if (timercmp(&ev->ev_timeout, &now, >))
break;
- next = RB_NEXT(event_tree, &timetree, ev);
+ next = RB_NEXT(event_tree, &base->timetree, ev);
- event_queue_remove(ev, EVLIST_TIMEOUT);
+ event_queue_remove(base, ev, EVLIST_TIMEOUT);
/* delete this event from the I/O queues */
event_del(ev);
}
void
-event_queue_remove(struct event *ev, int queue)
+event_queue_remove(struct event_base *base, struct event *ev, int queue)
{
int docount = 1;
docount = 0;
if (docount)
- event_count--;
+ base->event_count--;
ev->ev_flags &= ~queue;
switch (queue) {
case EVLIST_ACTIVE:
if (docount)
- event_count_active--;
- TAILQ_REMOVE(activequeues[ev->ev_pri], ev, ev_active_next);
+ base->event_count_active--;
+ TAILQ_REMOVE(base->activequeues[ev->ev_pri],
+ ev, ev_active_next);
break;
case EVLIST_SIGNAL:
TAILQ_REMOVE(&signalqueue, ev, ev_signal_next);
break;
case EVLIST_TIMEOUT:
- RB_REMOVE(event_tree, &timetree, ev);
+ RB_REMOVE(event_tree, &base->timetree, ev);
break;
case EVLIST_INSERTED:
- TAILQ_REMOVE(&eventqueue, ev, ev_next);
+ TAILQ_REMOVE(&base->eventqueue, ev, ev_next);
break;
default:
errx(1, "%s: unknown queue %x", __func__, queue);
}
void
-event_queue_insert(struct event *ev, int queue)
+event_queue_insert(struct event_base *base, struct event *ev, int queue)
{
int docount = 1;
docount = 0;
if (docount)
- event_count++;
+ base->event_count++;
ev->ev_flags |= queue;
switch (queue) {
case EVLIST_ACTIVE:
if (docount)
- event_count_active++;
- TAILQ_INSERT_TAIL(activequeues[ev->ev_pri], ev,ev_active_next);
+ base->event_count_active++;
+ TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri],
+ ev,ev_active_next);
break;
case EVLIST_SIGNAL:
TAILQ_INSERT_TAIL(&signalqueue, ev, ev_signal_next);
break;
case EVLIST_TIMEOUT: {
- struct event *tmp = RB_INSERT(event_tree, &timetree, ev);
+ struct event *tmp = RB_INSERT(event_tree, &base->timetree, ev);
assert(tmp == NULL);
break;
}
case EVLIST_INSERTED:
- TAILQ_INSERT_TAIL(&eventqueue, ev, ev_next);
+ TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
break;
default:
errx(1, "%s: unknown queue %x", __func__, queue);