Imported Upstream version 2.5.1
[debian/amanda] / common-src / event.c
index 6809ca117c3c61c1f9a364014d72dfce42ea417e..4ebdfef3c44092c2fe512679c253b770d2ed0c14 100644 (file)
@@ -24,7 +24,7 @@
  * file named AUTHORS, in the root directory of this distribution.
  */
 /*
- * $Id: event.c,v 1.20 2005/10/02 15:31:07 martinea Exp $
+ * $Id: event.c,v 1.24 2006/06/16 10:55:05 martinea Exp $
  *
  * Event handler.  Serializes different kinds of events to allow for
  * a uniform interface, central state storage, and centralized
@@ -86,53 +86,52 @@ static struct {
 static struct sigtabent {
     event_handle_t *handle;    /* handle for this signal */
     int score;                 /* number of signals recvd since last checked */
-    void (*oldhandler) P((int));/* old handler (for unsetting) */
+    void (*oldhandler)(int);/* old handler (for unsetting) */
 } sigtable[NSIG];
 
 #ifdef EVENT_DEBUG
-static const char *event_type2str P((event_type_t));
+static const char *event_type2str(event_type_t);
 #endif
 #define        fire(eh)        (*(eh)->fn)((eh)->arg)
-static void signal_handler P((int));
-static event_handle_t *gethandle P((void));
-static void puthandle P((event_handle_t *));
+static void signal_handler(int);
+static event_handle_t *gethandle(void);
+static void puthandle(event_handle_t *);
+static int event_loop_wait (event_handle_t *, const int);
 
 /*
  * Add a new event.  See the comment in event.h for what the arguments
  * mean.
  */
 event_handle_t *
-event_register(data, type, fn, arg)
-    event_id_t data;
-    event_type_t type;
-    event_fn_t fn;
-    void *arg;
+event_register(
+    event_id_t data,
+    event_type_t type,
+    event_fn_t fn,
+    void *arg)
 {
     event_handle_t *handle;
 
-    switch (type) {
-    case EV_READFD:
-    case EV_WRITEFD:
+    if ((type == EV_READFD) || (type == EV_WRITEFD)) {
        /* make sure we aren't given a high fd that will overflow a fd_set */
-       assert(data < FD_SETSIZE);
-       break;
-
-    case EV_SIG:
+       if (data >= FD_SETSIZE) {
+           error("event_register: Invalid file descriptor %d", data);
+           /*NOTREACHED*/
+       }
+#if !defined(__lint) /* Global checking knows that these are never called */
+    } else if (type == EV_SIG) {
        /* make sure signals are within range */
-       assert(data < NSIG);
-       /* make sure we don't double-register a signal */
-       assert(sigtable[data].handle == NULL);
-       break;
-
-    case EV_TIME:
-    case EV_WAIT:
-       break;
-
-    case EV_DEAD:
-    default:
-       /* callers can't register EV_DEAD */
-       assert(0);
-       break;
+       if (data >= NSIG) {
+           error("event_register: Invalid signal %d", data);
+           /*NOTREACHED*/
+       }
+       if (sigtable[data].handle != NULL) { 
+           error("event_register: signal %d already registered", data);
+           /*NOTREACHED*/
+       }
+    } else if (type >= EV_DEAD) {
+       error("event_register: Invalid event type %d", type);
+       /*NOTREACHED*/
+#endif
     }
 
     handle = gethandle();
@@ -144,8 +143,9 @@ event_register(data, type, fn, arg)
     eventq_add(eventq, handle);
     eventq.qlength++;
 
-    eventprintf(("%s: event: register: %X data=%lu, type=%s\n", debug_prefix_time(NULL), (int)handle,
-                handle->data, event_type2str(handle->type)));
+    eventprintf(("%s: event: register: %p->data=%lu, type=%s\n",
+               debug_prefix_time(NULL), handle, handle->data,
+               event_type2str(handle->type)));
     return (handle);
 }
 
@@ -155,14 +155,15 @@ event_register(data, type, fn, arg)
  * the event.
  */
 void
-event_release(handle)
-    event_handle_t *handle;
+event_release(
+    event_handle_t *handle)
 {
 
     assert(handle != NULL);
 
-    eventprintf(("%s: event: release (mark): %X data=%lu, type=%s\n", debug_prefix_time(NULL),
-       (int)handle, handle->data, event_type2str(handle->type)));
+    eventprintf(("%s: event: release (mark): %p data=%lu, type=%s\n",
+                debug_prefix_time(NULL), handle, handle->data,
+                event_type2str(handle->type)));
     assert(handle->type != EV_DEAD);
 
     /*
@@ -173,7 +174,7 @@ event_release(handle)
        struct sigtabent *se = &sigtable[handle->data];
 
        assert(se->handle == handle);
-       signal(handle->data, se->oldhandler);
+       signal((int)handle->data, se->oldhandler);
        se->handle = NULL;
        se->score = 0;
     }
@@ -194,20 +195,20 @@ event_release(handle)
  * Fire all EV_WAIT events waiting on the specified id.
  */
 int
-event_wakeup(id)
-    event_id_t id;
+event_wakeup(
+    event_id_t id)
 {
     event_handle_t *eh;
     int nwaken = 0;
 
-    eventprintf(("%s: event: wakeup: enter (%lu)\n", debug_prefix_time(NULL), id));
-
-    assert(id >= 0);
+    eventprintf(("%s: event: wakeup: enter (%lu)\n",
+                debug_prefix_time(NULL), id));
 
     for (eh = eventq_first(eventq); eh != NULL; eh = eventq_next(eh)) {
 
        if (eh->type == EV_WAIT && eh->data == id) {
-           eventprintf(("%s: event: wakeup: %X id=%lu\n", debug_prefix_time(NULL), (int)eh, id));
+           eventprintf(("%s: event: wakeup: %p id=%lu\n",
+                        debug_prefix_time(NULL), eh, id));
            fire(eh);
            nwaken++;
        }
@@ -222,27 +223,53 @@ event_wakeup(id)
  * we need to make sure we don't end up referencing a dead event handle.
  */
 void
-event_loop(dontblock)
-    const int dontblock;
+event_loop(
+    const int dontblock)
+{
+    event_loop_wait((event_handle_t *)NULL, dontblock);
+}
+
+
+
+int
+event_wait(
+    event_handle_t *eh)
+{
+    return event_loop_wait(eh, 0);
+}
+
+/*
+ * The event loop.  We need to be specially careful here with adds and
+ * deletes.  Since adds and deletes will often happen while this is running,
+ * we need to make sure we don't end up referencing a dead event handle.
+ */
+static int
+event_loop_wait(
+    event_handle_t *wait_eh,
+    const int       dontblock)
 {
 #ifdef ASSERTIONS
     static int entry = 0;
 #endif
     fd_set readfds, writefds, errfds, werrfds;
     struct timeval timeout, *tvptr;
-    int ntries, maxfd, rc, interval;
+    int ntries, maxfd, rc;
+    long interval;
     time_t curtime;
     event_handle_t *eh, *nexteh;
     struct sigtabent *se;
+    int event_wait_fired = 0;
+    int see_event;
 
-    eventprintf(("%s: event: loop: enter: dontblock=%d, qlength=%d\n", debug_prefix_time(NULL),
-                dontblock, eventq.qlength));
+    eventprintf(("%s: event: loop: enter: dontblock=%d, qlength=%d, eh=%p\n",
+                debug_prefix_time(NULL),
+                dontblock, eventq.qlength, wait_eh));
 
     /*
      * If we have no events, we have nothing to do
      */
     if (eventq.qlength == 0)
-       return;
+       return 0;
 
     /*
      * We must not be entered twice
@@ -259,11 +286,14 @@ event_loop(dontblock)
 
     do {
 #ifdef EVENT_DEBUG
-       eventprintf(("%s: event: loop: dontblock=%d, qlength=%d\n", debug_prefix_time(NULL), dontblock,
-           eventq.qlength));
+       eventprintf(("%s: event: loop: dontblock=%d, qlength=%d eh=%p\n",
+                    debug_prefix_time(NULL), dontblock, eventq.qlength,
+                    wait_eh));
        for (eh = eventq_first(eventq); eh != NULL; eh = eventq_next(eh)) {
-           eventprintf(("%s: %X: %s data=%lu fn=0x%x arg=0x%x\n", debug_prefix_time(NULL), (int)eh,
-               event_type2str(eh->type), eh->data, (int)eh->fn, (int)eh->arg));
+           eventprintf(("%s: %p): %s data=%lu fn=%p arg=%p\n",
+                        debug_prefix_time(NULL), eh,
+                        event_type2str(eh->type), eh->data, eh->fn,
+                        eh->arg));
        }
 #endif
        /*
@@ -294,6 +324,7 @@ event_loop(dontblock)
        FD_ZERO(&errfds);
        maxfd = 0;
 
+       see_event = (wait_eh == (event_handle_t *)NULL);
        /*
         * Run through each event handle and setup the events.
         * We save our next pointer early in case we GC some dead
@@ -308,18 +339,20 @@ event_loop(dontblock)
             * Read fds just get set into the select bitmask
             */
            case EV_READFD:
-               FD_SET(eh->data, &readfds);
-               FD_SET(eh->data, &errfds);
-               maxfd = max(maxfd, eh->data);
+               FD_SET((int)eh->data, &readfds);
+               FD_SET((int)eh->data, &errfds);
+               maxfd = max(maxfd, (int)eh->data);
+               see_event |= (eh == wait_eh);
                break;
 
            /*
             * Likewise with write fds
             */
            case EV_WRITEFD:
-               FD_SET(eh->data, &writefds);
-               FD_SET(eh->data, &errfds);
-               maxfd = max(maxfd, eh->data);
+               FD_SET((int)eh->data, &writefds);
+               FD_SET((int)eh->data, &errfds);
+               maxfd = max(maxfd, (int)eh->data);
+               see_event |= (eh == wait_eh);
                break;
 
            /*
@@ -328,6 +361,7 @@ event_loop(dontblock)
             */
            case EV_SIG:
                se = &sigtable[eh->data];
+               see_event |= (eh == wait_eh);
 
                if (se->handle == eh)
                    break;
@@ -336,7 +370,9 @@ event_loop(dontblock)
                assert(se->handle == NULL);
                se->handle = eh;
                se->score = 0;
-               se->oldhandler = signal(eh->data, signal_handler);
+               /*@ignore@*/
+               se->oldhandler = signal((int)eh->data, signal_handler);
+               /*@end@*/
                break;
 
            /*
@@ -350,7 +386,7 @@ event_loop(dontblock)
                if (eh->lastfired == -1)
                    eh->lastfired = curtime;
 
-               interval = eh->data - (curtime - eh->lastfired);
+               interval = (long)(eh->data - (curtime - eh->lastfired));
                if (interval < 0)
                    interval = 0;
 
@@ -361,12 +397,14 @@ event_loop(dontblock)
                    tvptr = &timeout;
                    timeout.tv_sec = interval;
                }
+               see_event |= (eh == wait_eh);
                break;
 
            /*
             * Wait events are processed immediately by event_wakeup()
             */
            case EV_WAIT:
+               see_event |= (eh == wait_eh);
                break;
 
            /*
@@ -383,13 +421,21 @@ event_loop(dontblock)
            }
        }
 
+       if(!see_event) {
+           assert(--entry == 0);
+           return 0;
+       }
+
        /*
         * Let 'er rip
         */
-       eventprintf(("%s: event: select: dontblock=%d, maxfd=%d, timeout=%ld\n", debug_prefix_time(NULL),
-           dontblock, maxfd, tvptr != NULL ? timeout.tv_sec : -1));
+       eventprintf((
+                   "%s: event: select: dontblock=%d, maxfd=%d, timeout=%ld\n",
+                   debug_prefix_time(NULL), dontblock, maxfd,
+                   tvptr != NULL ? timeout.tv_sec : -1));
        rc = select(maxfd + 1, &readfds, &writefds, &errfds, tvptr);
-       eventprintf(("%s: event: select returns %d\n", debug_prefix_time(NULL), rc));
+       eventprintf(("%s: event: select returns %d\n",
+                    debug_prefix_time(NULL), rc));
 
        /*
         * Select errors can mean many things.  Interrupted events should
@@ -398,8 +444,10 @@ event_loop(dontblock)
         */
        if (rc < 0) {
            if (errno != EINTR) {
-               if (++ntries > 5)
+               if (++ntries > 5) {
                    error("select failed: %s", strerror(errno));
+                   /*NOTREACHED*/
+               }
                continue;
            }
            /* proceed if errno == EINTR, we may have caught a signal */
@@ -420,24 +468,26 @@ event_loop(dontblock)
         * that are being polled for both reading and writing have
         * both of their poll events 'see' the error.
         */
-       memcpy(&werrfds, &errfds, sizeof(werrfds));
+       memcpy(&werrfds, &errfds, SIZEOF(werrfds));
 
        /*
         * Now run through the events and fire the ones that are ready.
         * Don't handle file descriptor events if the select failed.
         */
        for (eh = eventq_first(eventq); eh != NULL; eh = eventq_next(eh)) {
+
            switch (eh->type) {
 
            /*
             * Read fds: just fire the event if set in the bitmask
             */
            case EV_READFD:
-               if (FD_ISSET(eh->data, &readfds) ||
-                   FD_ISSET(eh->data, &errfds)) {
-                   FD_CLR(eh->data, &readfds);
-                   FD_CLR(eh->data, &errfds);
+               if (FD_ISSET((int)eh->data, &readfds) ||
+                   FD_ISSET((int)eh->data, &errfds)) {
+                   FD_CLR((int)eh->data, &readfds);
+                   FD_CLR((int)eh->data, &errfds);
                    fire(eh);
+                   if(eh == wait_eh) event_wait_fired = 1;
                }
                break;
 
@@ -445,11 +495,12 @@ event_loop(dontblock)
             * Write fds: same as Read fds
             */
            case EV_WRITEFD:
-               if (FD_ISSET(eh->data, &writefds) ||
-                   FD_ISSET(eh->data, &werrfds)) {
-                   FD_CLR(eh->data, &writefds);
-                   FD_CLR(eh->data, &werrfds);
+               if (FD_ISSET((int)eh->data, &writefds) ||
+                   FD_ISSET((int)eh->data, &werrfds)) {
+                   FD_CLR((int)eh->data, &writefds);
+                   FD_CLR((int)eh->data, &werrfds);
                    fire(eh);
+                   if(eh == wait_eh) event_wait_fired = 1;
                }
                break;
 
@@ -463,6 +514,7 @@ event_loop(dontblock)
                    assert(se->handle == eh);
                    se->score = 0;
                    fire(eh);
+                   if(eh == wait_eh) event_wait_fired = 1;
                }
                break;
 
@@ -473,9 +525,10 @@ event_loop(dontblock)
            case EV_TIME:
                if (eh->lastfired == -1)
                    eh->lastfired = curtime;
-               if (curtime - eh->lastfired >= eh->data) {
+               if ((curtime - eh->lastfired) >= (time_t)eh->data) {
                    eh->lastfired = curtime;
                    fire(eh);
+                   if(eh == wait_eh) event_wait_fired = 1;
                }
                break;
 
@@ -492,9 +545,11 @@ event_loop(dontblock)
                break;
            }
        }
-    } while (!dontblock && eventq.qlength > 0);
+    } while (!dontblock && eventq.qlength > 0 && event_wait_fired == 0);
 
     assert(--entry == 0);
+    
+    return (event_wait_fired == 1);
 }
 
 /*
@@ -502,11 +557,11 @@ event_loop(dontblock)
  * loop.
  */
 static void
-signal_handler(signo)
-    int signo;
+signal_handler(
+    int        signo)
 {
 
-    assert(signo >= 0 && signo < sizeof(sigtable) / sizeof(sigtable[0]));
+    assert((signo >= 0) && ((size_t)signo < (size_t)(sizeof(sigtable) / sizeof(sigtable[0]))));
     sigtable[signo].score++;
 }
 
@@ -515,7 +570,7 @@ signal_handler(signo)
  * alloc a new one.
  */
 static event_handle_t *
-gethandle()
+gethandle(void)
 {
     event_handle_t *eh;
 
@@ -526,7 +581,7 @@ gethandle()
        return (eh);
     }
     assert(cache.qlength == 0);
-    return (alloc(sizeof(*eh)));
+    return (alloc(SIZEOF(*eh)));
 }
 
 /*
@@ -534,8 +589,8 @@ gethandle()
  * Otherwise, free it.
  */
 static void
-puthandle(eh)
-    event_handle_t *eh;
+puthandle(
+    event_handle_t *eh)
 {
 
     if (cache.qlength > CACHEDEPTH) {
@@ -551,8 +606,8 @@ puthandle(eh)
  * Convert an event type into a string
  */
 static const char *
-event_type2str(type)
-    event_type_t type;
+event_type2str(
+    event_type_t type)
 {
     static const struct {
        event_type_t type;
@@ -567,9 +622,9 @@ event_type2str(type)
        X(EV_DEAD),
 #undef X
     };
-    int i;
+    size_t i;
 
-    for (i = 0; i < sizeof(event_types) / sizeof(event_types[0]); i++)
+    for (i = 0; i < (size_t)(sizeof(event_types) / sizeof(event_types[0])); i++)
        if (type == event_types[i].type)
            return (event_types[i].name);
     return ("BOGUS EVENT TYPE");