]> granicus.if.org Git - sudo/commitdiff
Get rid of cur and pending pointers in struct sudo_event_base. We
authorTodd C. Miller <Todd.Miller@courtesan.com>
Mon, 28 Oct 2013 17:13:45 +0000 (11:13 -0600)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Mon, 28 Oct 2013 17:13:45 +0000 (11:13 -0600)
now pop the first event off the active queue instead of using a
foreach loop with deferred removal of the event.
Add SUDO_EVQ_INSERTED and SUDO_EVQ_TIMEOUTS flags to indicate that
the event on the event queue and timeouts queue respectively.
No longer need to compare the timeout to {0,0} or compare the
event's base pointer to NULL to determine queue membership.

common/event.c
common/event_poll.c
common/event_select.c
include/sudo_event.h

index b439fc49dda6d64657b75a2c40a83030f06d71d4..248e5c5927f763200b8003249f18bd8b6b650e5a 100644 (file)
@@ -71,12 +71,12 @@ sudo_ev_base_alloc(void)
 void
 sudo_ev_base_free(struct sudo_event_base *base)
 {
-    struct sudo_event *next;
+    struct sudo_event *ev, *next;
     debug_decl(sudo_ev_base_free, SUDO_DEBUG_EVENT)
 
     /* Remove any existing events before freeing the base. */
-    TAILQ_FOREACH_SAFE(base->cur, &base->events, entries, next) {
-       sudo_ev_del(base, base->cur);
+    TAILQ_FOREACH_SAFE(ev, &base->events, entries, next) {
+       sudo_ev_del(base, ev);
     }
     sudo_ev_base_free_impl(base);
     efree(base);
@@ -108,7 +108,7 @@ sudo_ev_free(struct sudo_event *ev)
     debug_decl(sudo_ev_free, SUDO_DEBUG_EVENT)
 
     /* Make sure ev is not in use before freeing it. */
-    if (ev->base != NULL)
+    if (ISSET(ev->flags, SUDO_EVQ_INSERTED))
        (void)sudo_ev_del(NULL, ev);
     free(ev);
     debug_return;
@@ -120,8 +120,29 @@ sudo_ev_add(struct sudo_event_base *base, struct sudo_event *ev,
 {
     debug_decl(sudo_ev_add, SUDO_DEBUG_EVENT)
 
+    /* If no base specified, use existing one. */
+    if (base == NULL) {
+       if (ev->base == NULL) {
+           sudo_debug_printf(SUDO_DEBUG_ERROR, "%s: no base specified",
+               __func__);
+           debug_return_int(-1);
+       }
+       base = ev->base;
+    }
+
     /* Only add new events to the events list. */
-    if (ev->base == NULL) {
+    if (ISSET(ev->flags, SUDO_EVQ_INSERTED)) {
+       /* If event no longer has a timeout, remove from timeouts queue. */
+       if (timo == NULL && ISSET(ev->flags, SUDO_EVQ_TIMEOUTS)) {
+           sudo_debug_printf(SUDO_DEBUG_INFO,
+               "%s: removing event %p from timeouts queue", __func__, ev);
+           CLR(ev->flags, SUDO_EVQ_TIMEOUTS);
+           TAILQ_REMOVE(&base->timeouts, ev, timeouts_entries);
+       }
+    } else {
+       /* Add event to the base. */
+       sudo_debug_printf(SUDO_DEBUG_INFO, "%s: adding event %p to base %p",
+           __func__, ev, base);
        if (sudo_ev_add_impl(base, ev) != 0)
            debug_return_int(-1);
        ev->base = base;
@@ -130,21 +151,12 @@ sudo_ev_add(struct sudo_event_base *base, struct sudo_event *ev,
        } else {
            TAILQ_INSERT_TAIL(&base->events, ev, entries);
        }
-    } else {
-       /* If no base specified, use existing one. */
-       if (base == NULL)
-           base = ev->base;
-
-       /* If event no longer has a timeout, remove from timeouts queue. */
-       if (timo == NULL && timevalisset(&ev->timeout)) {
-           timevalclear(&ev->timeout);
-           TAILQ_REMOVE(&base->timeouts, ev, timeouts_entries);
-       }
+       SET(ev->flags, SUDO_EVQ_INSERTED);
     }
     /* Timeouts can be changed for existing events. */
     if (timo != NULL) {
        struct sudo_event *evtmp;
-       if (timevalisset(&ev->timeout)) {
+       if (ISSET(ev->flags, SUDO_EVQ_TIMEOUTS)) {
            /* Remove from timeouts list, then add back. */
            TAILQ_REMOVE(&base->timeouts, ev, timeouts_entries);
        }
@@ -161,9 +173,8 @@ sudo_ev_add(struct sudo_event_base *base, struct sudo_event *ev,
        } else {
            TAILQ_INSERT_TAIL(&base->timeouts, ev, timeouts_entries);
        }
+       SET(ev->flags, SUDO_EVQ_TIMEOUTS);
     }
-    /* Clear pending delete so adding from callback works properly. */
-    CLR(ev->flags, SUDO_EV_DELETE);
     debug_return_int(0);
 }
 
@@ -173,7 +184,7 @@ sudo_ev_del(struct sudo_event_base *base, struct sudo_event *ev)
     debug_decl(sudo_ev_del, SUDO_DEBUG_EVENT)
 
     /* Make sure event is really in the queue. */
-    if (ev->base == NULL) {
+    if (!ISSET(ev->flags, SUDO_EVQ_INSERTED)) {
        sudo_debug_printf(SUDO_DEBUG_INFO, "%s: event %p not in queue",
            __func__, ev);
        debug_return_int(0);
@@ -181,6 +192,11 @@ sudo_ev_del(struct sudo_event_base *base, struct sudo_event *ev)
 
     /* Check for event base mismatch, if one is specified. */
     if (base == NULL) {
+       if (ev->base == NULL) {
+           sudo_debug_printf(SUDO_DEBUG_ERROR, "%s: no base specified",
+               __func__);
+           debug_return_int(-1);
+       }
        base = ev->base;
     } else if (base != ev->base) {
        sudo_debug_printf(SUDO_DEBUG_ERROR, "%s: mismatch base %p, ev->base %p",
@@ -199,20 +215,14 @@ sudo_ev_del(struct sudo_event_base *base, struct sudo_event *ev)
     TAILQ_REMOVE(&base->events, ev, entries);
 
     /* Unlink from timeouts list. */
-    if (ISSET(ev->events, SUDO_EV_TIMEOUT) && timevalisset(&ev->timeout))
+    if (ISSET(ev->flags, SUDO_EVQ_TIMEOUTS))
        TAILQ_REMOVE(&base->timeouts, ev, timeouts_entries);
 
     /* Unlink from active list and update base pointers as needed. */
-    if (ISSET(ev->flags, SUDO_EV_ACTIVE)) {
+    if (ISSET(ev->flags, SUDO_EVQ_ACTIVE))
        TAILQ_REMOVE(&base->active, ev, active_entries);
-       if (ev == base->pending)
-           base->pending = TAILQ_NEXT(ev, active_entries);
-       if (ev == base->cur)
-           base->cur = NULL;
-    }
 
     /* Mark event unused. */
-    ev->base = NULL;
     ev->flags = 0;
     ev->pfd_idx = -1;
 
@@ -264,11 +274,11 @@ rescan:
                if (timevalcmp(&ev->timeout, &now, >))
                    break;
                /* Remove from timeouts list. */
-               timevalclear(&ev->timeout);
+               CLR(ev->flags, SUDO_EVQ_TIMEOUTS);
                TAILQ_REMOVE(&base->timeouts, ev, timeouts_entries);
                /* Make event active. */
                ev->revents = SUDO_EV_TIMEOUT;
-               SET(ev->flags, SUDO_EV_ACTIVE);
+               SET(ev->flags, SUDO_EVQ_ACTIVE);
                TAILQ_INSERT_TAIL(&base->active, ev, active_entries);
            }
            break;
@@ -283,32 +293,27 @@ rescan:
         * it can be cleared by sudo_ev_del().  This prevents a use
         * after free if the callback frees its own event.
         */
-       TAILQ_FOREACH_SAFE(base->cur, &base->active, active_entries, base->pending) {
-           if (!ISSET(base->cur->events, SUDO_EV_PERSIST))
-               SET(base->cur->flags, SUDO_EV_DELETE);
-           base->cur->callback(base->cur->fd, base->cur->revents,
-               base->cur->closure == sudo_ev_self_cbarg() ? base->cur : base->cur->closure);
-           if (base->cur != NULL) {
-               CLR(base->cur->flags, SUDO_EV_ACTIVE);
-               if (ISSET(base->cur->flags, SUDO_EV_DELETE))
-                   sudo_ev_del(base, base->cur);
-           }
+       while ((ev = TAILQ_FIRST(&base->active)) != NULL) {
+           /* Pop first event off the active queue. */
+           CLR(ev->flags, SUDO_EVQ_ACTIVE);
+           TAILQ_REMOVE(&base->active, ev, active_entries);
+           /* Remove from base unless persistent. */
+           if (!ISSET(ev->events, SUDO_EV_PERSIST))
+               sudo_ev_del(base, ev);
+           ev->callback(ev->fd, ev->revents,
+               ev->closure == sudo_ev_self_cbarg() ? ev : ev->closure);
            if (ISSET(base->flags, SUDO_EVBASE_LOOPBREAK)) {
                /* stop processing events immediately */
                SET(base->flags, SUDO_EVBASE_GOT_BREAK);
-               base->pending = NULL;
                goto done;
            }
            if (ISSET(base->flags, SUDO_EVBASE_LOOPCONT)) {
                /* rescan events and start polling again */
                CLR(base->flags, SUDO_EVBASE_LOOPCONT);
-               if (!ISSET(flags, SUDO_EVLOOP_ONCE)) {
-                   base->pending = NULL;
+               if (!ISSET(flags, SUDO_EVLOOP_ONCE))
                    goto rescan;
-               }
            }
        }
-       base->pending = NULL;
        if (ISSET(base->flags, SUDO_EVBASE_LOOPEXIT)) {
            /* exit loop after once through */
            SET(base->flags, SUDO_EVBASE_GOT_EXIT);
index d84c90bc17f5fea47a8965d1c2e78386304a7578..bc06a6f1f212d04c97224d8aa5e5e160a34433c3 100644 (file)
@@ -170,7 +170,7 @@ sudo_ev_scan_impl(struct sudo_event_base *base, int flags)
                    what |= (ev->events & SUDO_EV_WRITE);
                /* Make event active. */
                ev->revents = what;
-               SET(ev->flags, SUDO_EV_ACTIVE);
+               SET(ev->flags, SUDO_EVQ_ACTIVE);
                TAILQ_INSERT_TAIL(&base->active, ev, active_entries);
            }
        }
index 48a87098db1ef3cf165d109d513bb47dd40b5528..c2b3dc7e1d448496e128a6a1d1f3b034802c8e85 100644 (file)
@@ -173,7 +173,7 @@ sudo_ev_scan_impl(struct sudo_event_base *base, int flags)
            if (what != 0) {
                /* Make event active. */
                ev->revents = what;
-               SET(ev->flags, SUDO_EV_ACTIVE);
+               SET(ev->flags, SUDO_EVQ_ACTIVE);
                TAILQ_INSERT_TAIL(&base->active, ev, active_entries);
            }
        }
index c3a007be47b8ae2cee53846daf3f99b1532b6fd8..77e44597e8c8dfd7142486d412b100bddaa53973 100644 (file)
@@ -26,8 +26,9 @@
 #define SUDO_EV_PERSIST                0x08    /* persist until deleted */
 
 /* Event flags (internal) */
-#define SUDO_EV_ACTIVE         0x01    /* event is on the active queue */
-#define SUDO_EV_DELETE         0x02    /* deletion pending */
+#define SUDO_EVQ_INSERTED      0x01    /* event is on the event queue */
+#define SUDO_EVQ_ACTIVE                0x02    /* event is on the active queue */
+#define SUDO_EVQ_TIMEOUTS      0x04    /* event is on the timeouts queue */
 
 /* Event loop flags */
 #define SUDO_EVLOOP_ONCE       0x01    /* Only run once through the loop */
@@ -65,8 +66,6 @@ struct sudo_event_base {
     struct sudo_event_list events; /* tail queue of all events */
     struct sudo_event_list active; /* tail queue of active events */
     struct sudo_event_list timeouts; /* tail queue of timeout events */
-    struct sudo_event *cur;    /* current active event being serviced */
-    struct sudo_event *pending;        /* next active event to be serviced */
 #ifdef HAVE_POLL
     struct pollfd *pfds;       /* array of struct pollfd */
     int pfd_max;               /* size of the pfds array */