/* Routines for time-delayed actions.
*
* IRC Services is copyright (c) 1996-2007 Andrew Church.
* E-mail: <achurch@achurch.org>
* 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);
}
/*************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1