]> granicus.if.org Git - libevent/commitdiff
restructure the code to make event activation independent of regular event logic
authorNiels Provos <provos@gmail.com>
Sun, 16 Dec 2007 04:10:30 +0000 (04:10 +0000)
committerNiels Provos <provos@gmail.com>
Sun, 16 Dec 2007 04:10:30 +0000 (04:10 +0000)
svn:r594

ChangeLog
event-internal.h
event.c
event.h

index 60278eceabbbf38dfafa3bcdb3cdc18fc1706f30..cd856a1959fd397eced8cb4d8bdb5e4f4d28213b 100644 (file)
--- 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:
index f61757c118bb62d62bd072a409c055d0f5c9f88b..c1f4a2dc8d7abaf0810f0b3686af20abb9ccb434 100644 (file)
@@ -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 <sys/queue.h> */
 #ifndef HAVE_TAILQFOREACH
 #define        TAILQ_FIRST(head)               ((head)->tqh_first)
diff --git a/event.c b/event.c
index 9b54cfcc1bb54fa7f6d4b0fe582e482a858bdb7d..4c19915220599e55ea408082cc79229088ccea5c 100644 (file)
--- 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 86474dfc10a25e0b865b7fb16768fa9e588affe3..c0bd8aca84ef78e9e2ca6e5d4d63021db6ed14e9 100644 (file)
--- 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 <sys/queue.h> */
 #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