/******************************************/ /* event.c 0.2.0 (1999-Dec-17-Thu) */ /* Adam M. Costello */ /******************************************/ /* An event queue. Implements the interfaces */ /* of timer.h 0.2.x and timer_expire.h 0.1.x. */ /* This is ANSI C code. */ #include #include #include "timer_expire.h" #include "timer.h" #include "warnf.h" /* This is an inefficient implementation, using a linked list */ /* rather than a hash table or timing wheel. But it's just a */ /* small-scale simulation, so it doesn't matter. */ struct timer { double when; /* Time at which the timer will expire. */ unsigned long serial; /* Number of timers set before this one. */ timer_handler *expire; /* Function that will handle the expiration. */ void *who, *what; /* Arguments to pass to expire(). */ struct timer *next; /* Timer scheduled to expire after this one. */ }; static double now = 0.0; /* The current time. */ static struct timer *first = 0; /* Timer scheduled to expire first. */ static struct timer *avail = 0; /* List of available timer structures. */ static unsigned long nextserial; /* Number of timers that have been set. */ double timer_now(void) { return now; } double timer_next(void) { return first ? first->when : now; } timer_id timer_set(timer_handler *expire, double when, void *who, void *what) { struct timer *timer, *p, *pn; unsigned long serial; timer_id id; if (!avail) { avail = malloc(sizeof (struct timer)); if (!avail) failf(out_of_memory); avail->next = 0; } timer = avail; avail = avail->next; if (when < now) when = now; serial = nextserial++; timer->when = when; timer->serial = serial; timer->expire = expire; timer->who = who; timer->what = what; if (!first || first->when > when) { timer->next = first; first = timer; } else { for (p = first;;) { pn = p->next; if (!pn || pn->when > when) break; p = pn; } timer->next = pn; p->next = timer; } id.timer = timer; id.serial = serial; return id; } int timer_cancel(timer_id timer) { struct timer *p, *pn; if (!first || timer.timer->serial != timer.serial) return 0; if (first == timer.timer) { first = first->next; timer.timer->next = avail; avail = timer.timer; return 1; } for (p = first;;) { pn = p->next; if (!pn) return 0; if (pn == timer.timer) break; p = pn; } p->next = pn->next; pn->next = avail; avail = pn; return 1; } int timer_expire(void) { struct timer *timer; if (!first) return 0; timer = first; first = first->next; timer->next = avail; avail = timer; assert(now <= timer->when); now = timer->when; timer->expire(now, timer->who, timer->what); return 1; }