2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1999 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: event.c,v 1.24 2006/06/16 10:55:05 martinea Exp $
29 * Event handler. Serializes different kinds of events to allow for
30 * a uniform interface, central state storage, and centralized
31 * interdependency logic.
34 /*#define EVENT_DEBUG*/
37 #define eventprintf(x) dbprintf(x)
39 #define eventprintf(x)
47 * The opaque handle passed back to the caller. This is typedefed to
48 * event_handle_t in our header file.
51 event_fn_t fn; /* function to call when this fires */
52 void *arg; /* argument to pass to previous function */
53 event_type_t type; /* type of event */
54 event_id_t data; /* type data */
55 time_t lastfired; /* timestamp of last fired (EV_TIME only) */
56 LIST_ENTRY(event_handle) le; /* queue handle */
60 * eventq is a queue of currently active events.
61 * cache is a queue of unused handles. We keep a few around to avoid
62 * malloc overhead when doing a lot of register/releases.
65 LIST_HEAD(, event_handle) listhead;
68 LIST_HEAD_INITIALIZER(eventq.listhead), 0
70 LIST_HEAD_INITIALIZER(eventq.listhead), 0
72 #define eventq_first(q) LIST_FIRST(&q.listhead)
73 #define eventq_next(eh) LIST_NEXT(eh, le)
74 #define eventq_add(q, eh) LIST_INSERT_HEAD(&q.listhead, eh, le);
75 #define eventq_remove(eh) LIST_REMOVE(eh, le);
78 * How many items we can have in the handle cache before we start
84 * A table of currently set signal handlers.
86 static struct sigtabent {
87 event_handle_t *handle; /* handle for this signal */
88 int score; /* number of signals recvd since last checked */
89 void (*oldhandler)(int);/* old handler (for unsetting) */
93 static const char *event_type2str(event_type_t);
95 #define fire(eh) (*(eh)->fn)((eh)->arg)
96 static void signal_handler(int);
97 static event_handle_t *gethandle(void);
98 static void puthandle(event_handle_t *);
99 static int event_loop_wait (event_handle_t *, const int);
102 * Add a new event. See the comment in event.h for what the arguments
112 event_handle_t *handle;
114 if ((type == EV_READFD) || (type == EV_WRITEFD)) {
115 /* make sure we aren't given a high fd that will overflow a fd_set */
116 if (data >= FD_SETSIZE) {
117 error("event_register: Invalid file descriptor %d", data);
120 #if !defined(__lint) /* Global checking knows that these are never called */
121 } else if (type == EV_SIG) {
122 /* make sure signals are within range */
124 error("event_register: Invalid signal %d", data);
127 if (sigtable[data].handle != NULL) {
128 error("event_register: signal %d already registered", data);
131 } else if (type >= EV_DEAD) {
132 error("event_register: Invalid event type %d", type);
137 handle = gethandle();
142 handle->lastfired = -1;
143 eventq_add(eventq, handle);
146 eventprintf(("%s: event: register: %p->data=%lu, type=%s\n",
147 debug_prefix_time(NULL), handle, handle->data,
148 event_type2str(handle->type)));
153 * Mark an event to be released. Because we may be traversing the queue
154 * when this is called, we must wait until later to actually remove
159 event_handle_t *handle)
162 assert(handle != NULL);
164 eventprintf(("%s: event: release (mark): %p data=%lu, type=%s\n",
165 debug_prefix_time(NULL), handle, handle->data,
166 event_type2str(handle->type)));
167 assert(handle->type != EV_DEAD);
170 * For signal events, we need to specially remove then from the
171 * signal event table.
173 if (handle->type == EV_SIG) {
174 struct sigtabent *se = &sigtable[handle->data];
176 assert(se->handle == handle);
177 signal((int)handle->data, se->oldhandler);
183 * Decrement the qlength now since this is no longer a real
189 * Mark it as dead and leave it for the loop to remove.
191 handle->type = EV_DEAD;
195 * Fire all EV_WAIT events waiting on the specified id.
204 eventprintf(("%s: event: wakeup: enter (%lu)\n",
205 debug_prefix_time(NULL), id));
207 for (eh = eventq_first(eventq); eh != NULL; eh = eventq_next(eh)) {
209 if (eh->type == EV_WAIT && eh->data == id) {
210 eventprintf(("%s: event: wakeup: %p id=%lu\n",
211 debug_prefix_time(NULL), eh, id));
221 * The event loop. We need to be specially careful here with adds and
222 * deletes. Since adds and deletes will often happen while this is running,
223 * we need to make sure we don't end up referencing a dead event handle.
229 event_loop_wait((event_handle_t *)NULL, dontblock);
238 return event_loop_wait(eh, 0);
242 * The event loop. We need to be specially careful here with adds and
243 * deletes. Since adds and deletes will often happen while this is running,
244 * we need to make sure we don't end up referencing a dead event handle.
248 event_handle_t *wait_eh,
252 static int entry = 0;
254 fd_set readfds, writefds, errfds, werrfds;
255 struct timeval timeout, *tvptr;
256 int ntries, maxfd, rc;
259 event_handle_t *eh, *nexteh;
260 struct sigtabent *se;
261 int event_wait_fired = 0;
264 eventprintf(("%s: event: loop: enter: dontblock=%d, qlength=%d, eh=%p\n",
265 debug_prefix_time(NULL),
266 dontblock, eventq.qlength, wait_eh));
269 * If we have no events, we have nothing to do
271 if (eventq.qlength == 0)
275 * We must not be entered twice
277 assert(++entry == 1);
282 * Save a copy of the current time once, to reduce syscall load
285 curtime = time(NULL);
289 eventprintf(("%s: event: loop: dontblock=%d, qlength=%d eh=%p\n",
290 debug_prefix_time(NULL), dontblock, eventq.qlength,
292 for (eh = eventq_first(eventq); eh != NULL; eh = eventq_next(eh)) {
293 eventprintf(("%s: %p): %s data=%lu fn=%p arg=%p\n",
294 debug_prefix_time(NULL), eh,
295 event_type2str(eh->type), eh->data, eh->fn,
300 * Set ourselves up with no timeout initially.
306 * If we can block, initially set the tvptr to NULL. If
307 * we come across timeout events in the loop below, they
308 * will set it to an appropriate buffer. If we don't
309 * see any timeout events, then tvptr will remain NULL
310 * and the select will properly block indefinately.
312 * If we can't block, set it to point to the timeout buf above.
320 * Rebuild the select bitmasks each time.
327 see_event = (wait_eh == (event_handle_t *)NULL);
329 * Run through each event handle and setup the events.
330 * We save our next pointer early in case we GC some dead
333 for (eh = eventq_first(eventq); eh != NULL; eh = nexteh) {
334 nexteh = eventq_next(eh);
339 * Read fds just get set into the select bitmask
342 FD_SET((int)eh->data, &readfds);
343 FD_SET((int)eh->data, &errfds);
344 maxfd = max(maxfd, (int)eh->data);
345 see_event |= (eh == wait_eh);
349 * Likewise with write fds
352 FD_SET((int)eh->data, &writefds);
353 FD_SET((int)eh->data, &errfds);
354 maxfd = max(maxfd, (int)eh->data);
355 see_event |= (eh == wait_eh);
359 * Only set signals that aren't already set to avoid unnecessary
363 se = &sigtable[eh->data];
364 see_event |= (eh == wait_eh);
366 if (se->handle == eh)
369 /* no previous handle */
370 assert(se->handle == NULL);
374 se->oldhandler = signal((int)eh->data, signal_handler);
379 * Compute the timeout for this select
382 /* if we're not supposed to block, then leave it at 0 */
386 if (eh->lastfired == -1)
387 eh->lastfired = curtime;
389 interval = (long)(eh->data - (curtime - eh->lastfired));
394 timeout.tv_sec = min(timeout.tv_sec, interval);
396 /* this is the first timeout */
398 timeout.tv_sec = interval;
400 see_event |= (eh == wait_eh);
404 * Wait events are processed immediately by event_wakeup()
407 see_event |= (eh == wait_eh);
425 assert(--entry == 0);
433 "%s: event: select: dontblock=%d, maxfd=%d, timeout=%ld\n",
434 debug_prefix_time(NULL), dontblock, maxfd,
435 tvptr != NULL ? timeout.tv_sec : -1));
436 rc = select(maxfd + 1, &readfds, &writefds, &errfds, tvptr);
437 eventprintf(("%s: event: select returns %d\n",
438 debug_prefix_time(NULL), rc));
441 * Select errors can mean many things. Interrupted events should
442 * not be fatal, since they could be delivered signals which still
443 * need to have their events fired.
446 if (errno != EINTR) {
448 error("select failed: %s", strerror(errno));
453 /* proceed if errno == EINTR, we may have caught a signal */
455 /* contents cannot be trusted */
462 * Grab the current time again for use in timed events.
464 curtime = time(NULL);
467 * We need to copy the errfds into werrfds, so file descriptors
468 * that are being polled for both reading and writing have
469 * both of their poll events 'see' the error.
471 memcpy(&werrfds, &errfds, SIZEOF(werrfds));
474 * Now run through the events and fire the ones that are ready.
475 * Don't handle file descriptor events if the select failed.
477 for (eh = eventq_first(eventq); eh != NULL; eh = eventq_next(eh)) {
482 * Read fds: just fire the event if set in the bitmask
485 if (FD_ISSET((int)eh->data, &readfds) ||
486 FD_ISSET((int)eh->data, &errfds)) {
487 FD_CLR((int)eh->data, &readfds);
488 FD_CLR((int)eh->data, &errfds);
490 if(eh == wait_eh) event_wait_fired = 1;
495 * Write fds: same as Read fds
498 if (FD_ISSET((int)eh->data, &writefds) ||
499 FD_ISSET((int)eh->data, &werrfds)) {
500 FD_CLR((int)eh->data, &writefds);
501 FD_CLR((int)eh->data, &werrfds);
503 if(eh == wait_eh) event_wait_fired = 1;
508 * Signal events: check the score for fires, and run the
509 * event if we got one.
512 se = &sigtable[eh->data];
514 assert(se->handle == eh);
517 if(eh == wait_eh) event_wait_fired = 1;
522 * Timed events: check the interval elapsed since last fired,
523 * and set it off if greater or equal to requested interval.
526 if (eh->lastfired == -1)
527 eh->lastfired = curtime;
528 if ((curtime - eh->lastfired) >= (time_t)eh->data) {
529 eh->lastfired = curtime;
531 if(eh == wait_eh) event_wait_fired = 1;
536 * Wait events are handled immediately by event_wakeup()
537 * Dead events are handled by the pre-select loop.
548 } while (!dontblock && eventq.qlength > 0 && event_wait_fired == 0);
550 assert(--entry == 0);
552 return (event_wait_fired == 1);
556 * Generic signal handler. Used to count caught signals for the event
564 assert((signo >= 0) && ((size_t)signo < (size_t)(sizeof(sigtable) / sizeof(sigtable[0]))));
565 sigtable[signo].score++;
569 * Return a new handle. Take from the handle cache if not empty. Otherwise,
572 static event_handle_t *
577 if ((eh = eventq_first(cache)) != NULL) {
578 assert(cache.qlength > 0);
583 assert(cache.qlength == 0);
584 return (alloc(SIZEOF(*eh)));
588 * Free a handle. If there's space in the handle cache, put it there.
589 * Otherwise, free it.
596 if (cache.qlength > CACHEDEPTH) {
600 eventq_add(cache, eh);
606 * Convert an event type into a string
612 static const struct {
616 #define X(s) { s, stringize(s) }
627 for (i = 0; i < (size_t)(sizeof(event_types) / sizeof(event_types[0])); i++)
628 if (type == event_types[i].type)
629 return (event_types[i].name);
630 return ("BOGUS EVENT TYPE");
632 #endif /* EVENT_DEBUG */