* 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
* interdependency logic.
*/
-/*#define EVENT_DEBUG*/
-
-#ifdef EVENT_DEBUG
-#define eventprintf(x) dbprintf(x)
-#else
-#define eventprintf(x)
-#endif
-
#include "amanda.h"
#include "event.h"
#include "queue.h"
+#include "conffile.h"
+
+#define event_debug(i, ...) do { \
+ if ((i) <= debug_event) { \
+ dbprintf(__VA_ARGS__); \
+ } \
+} while (0)
/*
* The opaque handle passed back to the caller. This is typedefed to
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));
-#endif
+static const char *event_type2str(event_type_t);
#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 >= (int)FD_SETSIZE) {
+ error(_("event_register: Invalid file descriptor %lu"), 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 %lu"), data);
+ /*NOTREACHED*/
+ }
+ if (sigtable[data].handle != NULL) {
+ error(_("event_register: signal %lu already registered"), data);
+ /*NOTREACHED*/
+ }
+ } else if (type >= EV_DEAD) {
+ error(_("event_register: Invalid event type %d"), type);
+ /*NOTREACHED*/
+#endif
}
handle = gethandle();
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)));
+ event_debug(1, _("event: register: %p->data=%lu, type=%s\n"),
+ handle, handle->data, event_type2str(handle->type));
return (handle);
}
* 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)));
+ event_debug(1, _("event: release (mark): %p data=%lu, type=%s\n"),
+ handle, handle->data,
+ event_type2str(handle->type));
assert(handle->type != EV_DEAD);
/*
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;
}
* 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);
+ event_debug(1, _("event: wakeup: enter (%lu)\n"), 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));
+ event_debug(1, _("event: wakeup: %p id=%lu\n"), eh, id);
fire(eh);
nwaken++;
}
* 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;
+ SELECT_ARG_TYPE 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));
+ event_debug(1, _("event: loop: enter: dontblock=%d, qlength=%d, eh=%p\n"),
+ 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
curtime = time(NULL);
do {
-#ifdef EVENT_DEBUG
- eventprintf(("%s: event: loop: dontblock=%d, qlength=%d\n", debug_prefix_time(NULL), dontblock,
- eventq.qlength));
- 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));
+ if (debug_event >= 1) {
+ event_debug(1, _("event: loop: dontblock=%d, qlength=%d eh=%p\n"),
+ dontblock, eventq.qlength, wait_eh);
+ for (eh = eventq_first(eventq); eh != NULL; eh = eventq_next(eh)) {
+ event_debug(1, _("%p): %s data=%lu fn=%p arg=%p\n"),
+ eh, event_type2str(eh->type), eh->data, eh->fn,
+ eh->arg);
+ }
}
-#endif
/*
* Set ourselves up with no timeout initially.
*/
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
* 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;
/*
*/
case EV_SIG:
se = &sigtable[eh->data];
+ see_event |= (eh == wait_eh);
if (se->handle == eh)
break;
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;
/*
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;
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;
/*
}
}
+ 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));
+ event_debug(1,
+ _("event: select: dontblock=%d, maxfd=%d, timeout=%ld\n"),
+ 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));
+ event_debug(1, _("event: select returns %d\n"), rc);
/*
* Select errors can mean many things. Interrupted events should
*/
if (rc < 0) {
if (errno != EINTR) {
- if (++ntries > 5)
- error("select failed: %s", strerror(errno));
+ if (++ntries > 5) {
+ error(_("select failed: %s"), strerror(errno));
+ /*NOTREACHED*/
+ }
continue;
}
/* proceed if errno == EINTR, we may have caught a signal */
* 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;
* 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;
assert(se->handle == eh);
se->score = 0;
fire(eh);
+ if(eh == wait_eh) event_wait_fired = 1;
}
break;
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;
break;
}
}
- } while (!dontblock && eventq.qlength > 0);
+ } while (!dontblock && eventq.qlength > 0 && event_wait_fired == 0);
assert(--entry == 0);
+
+ return (event_wait_fired == 1);
}
/*
* 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++;
}
* alloc a new one.
*/
static event_handle_t *
-gethandle()
+gethandle(void)
{
event_handle_t *eh;
return (eh);
}
assert(cache.qlength == 0);
- return (alloc(sizeof(*eh)));
+ return (alloc(SIZEOF(*eh)));
}
/*
* Otherwise, free it.
*/
static void
-puthandle(eh)
- event_handle_t *eh;
+puthandle(
+ event_handle_t *eh)
{
if (cache.qlength > CACHEDEPTH) {
cache.qlength++;
}
-#ifdef EVENT_DEBUG
/*
* 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;
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");
+ return (_("BOGUS EVENT TYPE"));
}
-#endif /* EVENT_DEBUG */