/* Routines for time-delayed actions. * * IRC Services is copyright (c) 1996-2007 Andrew Church. * E-mail: * Parts written by Andrew Kempe and others. * This program is free but copyrighted software; see the file COPYING for * details. */ #include "services.h" #define IN_TIMEOUT_C #include "timeout.h" /*************************************************************************/ static Timeout *timeouts = NULL; static int checking_timeouts = 0; /*************************************************************************/ #ifdef DEBUG_COMMANDS /* Send the timeout list to the given user. */ void send_timeout_list(User *u) { Timeout *to; uint32 now = time_msec(); notice(ServerName, u->nick, "Now: %u.%03u", now/1000, now%1000); LIST_FOREACH (to, timeouts) { notice(ServerName, u->nick, "%p: %u.%03u: %p (%p)", to, to->timeout/1000, to->timeout%1000, to->code, to->data); } } #endif /* DEBUG_COMMANDS */ /*************************************************************************/ /* Check the timeout list for any pending actions. */ void check_timeouts(void) { Timeout *to, *to2; uint32 now = time_msec(); if (checking_timeouts) fatal("check_timeouts() called recursively!"); checking_timeouts = 1; if (debug >= 2) { log("debug: Checking timeouts at time_msec = %u.%03u", now/1000, now%1000); } LIST_FOREACH_SAFE (to, timeouts, to2) { if (to->timeout) { if ((int32)(to->timeout - now) > 0) continue; if (debug >= 3) { log("debug: Running timeout %p (code=%p repeat=%d)", to, to->code, to->repeat); } to->code(to); if (to->repeat) { to->timeout = now + to->repeat; continue; } } LIST_REMOVE(to, timeouts); free(to); } if (debug >= 2) log("debug: Finished timeout list"); checking_timeouts = 0; } /*************************************************************************/ /* Add a timeout to the list to be triggered in `delay' seconds. If * `repeat' is nonzero, do not delete the timeout after it is triggered. * This must maintain the property that timeouts added from within a * timeout routine do not get checked during that run of the timeout list. */ Timeout *add_timeout(int delay, void (*code)(Timeout *), int repeat) { if (delay > 4294967) /* 2^32 / 1000 */ delay = 4294967; return add_timeout_ms((uint32)delay*1000, code, repeat); } /*************************************************************************/ Timeout *add_timeout_ms(uint32 delay, void (*code)(Timeout *), int repeat) { Timeout *t = smalloc(sizeof(Timeout)); t->settime = time(NULL); t->timeout = time_msec() + delay; t->code = code; t->data = NULL; t->repeat = repeat ? delay : 0; LIST_INSERT(t, timeouts); return t; } /*************************************************************************/ /* Remove a timeout from the list (if it's there). */ void del_timeout(Timeout *t) { Timeout *ptr; LIST_FOREACH (ptr, timeouts) { if (ptr == t) break; } if (!ptr) { log("timeout: BUG: attempted to remove timeout %p (not on list)", t); return; } if (checking_timeouts) { t->timeout = 0; /* delete it when we hit it in the list */ return; } LIST_REMOVE(t, timeouts); free(t); } /*************************************************************************/