NetBSD/usr.sbin/mrouted/callout.c

202 lines
3.8 KiB
C

/* $NetBSD: callout.c,v 1.2 1995/10/09 03:51:34 thorpej Exp $ */
/*
* The mrouted program is covered by the license in the accompanying file
* named "LICENSE". Use of the mrouted program represents acceptance of
* the terms and conditions listed in that file.
*
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
*/
#include "defs.h"
/* the code below implements a callout queue */
static int id = 0;
static struct timeout_q *Q = 0; /* pointer to the beginning of timeout queue */
static int in_callout= 0;
typedef void (* cfunc_t)();
struct timeout_q {
struct timeout_q *next; /* next event */
int id;
cfunc_t func ; /* function to call */
char *data; /* func's data */
int time; /* time offset to next event*/
};
static void print_Q();
void callout_init()
{
Q = (struct timeout_q *) 0;
}
/*
* signal handler for SIGALARM that is called once every second
*/
void age_callout_queue()
{
struct timeout_q *ptr;
if (in_callout)
return;
in_callout = 1;
ptr = Q;
while (ptr){
if (!ptr->time ) {
/* timeout has happened */
if(ptr->func)
ptr->func(ptr->data);
Q = Q->next;
free(ptr);
ptr = Q;
}
else {
ptr->time --;
#ifdef IGMP_DEBUG
log(LOG_DEBUG,0,"[callout, age_callout_queue] -- time (%d)", ptr->time);
#endif IGMP_DEBUG
in_callout = 0; return;
}
}
in_callout = 0;
return;
}
/*
* sets the timer
*/
int timer_setTimer(delay, action, data)
int delay; /* number of units for timeout */
cfunc_t action; /* function to be called on timeout */
char *data; /* what to call the timeout function with */
{
struct timeout_q *ptr, *node, *prev;
if (in_callout)
return -1;
in_callout = 1;
/* create a node */
node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
if (node == 0) {
log(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n");
in_callout = 0;
return -1;
}
node->func = action;
node->data = data;
node->time = delay;
node->next = 0;
node->id = ++id;
prev = ptr = Q;
/* insert node in the queue */
/* if the queue is empty, insert the node and return */
if (!Q)
Q = node;
else {
/* chase the pointer looking for the right place */
while (ptr){
if (delay < ptr->time){
/* right place */
node->next = ptr;
if (ptr == Q)
Q = node;
else
prev->next = node;
ptr->time -= node->time;
print_Q();
in_callout = 0;
return node->id;
}
else {
/* keep moving */
delay -= ptr->time; node->time = delay;
prev = ptr;
ptr = ptr->next;
}
}
prev->next = node;
}
print_Q();
in_callout = 0;
return node->id;
}
/* clears the associated timer */
void timer_clearTimer( timer_id)
int timer_id;
{
struct timeout_q *ptr, *prev;
if (in_callout) return;
in_callout = 1;
if ( !timer_id ) {in_callout = 0; return;}
prev = ptr = Q;
/*
* find the right node, delete it. the subsequent node's time
* gets bumped up
*/
print_Q();
while (ptr){
if (ptr->id == timer_id){
/* got the right node */
/* unlink it from the queue */
if ( ptr == Q)
Q = Q->next;
else
prev->next = ptr->next;
/* increment next node if any */
if (ptr->next != 0)
(ptr->next)->time += ptr->time;
free(ptr->data);
free(ptr);
print_Q();
in_callout = 0;
return;
}
prev = ptr;
ptr = ptr->next;
}
print_Q();
in_callout = 0;
}
/*
* debugging utility
*/
static void print_Q()
{
#ifdef IGMP_DEBUG
struct timeout_q *ptr;
for(ptr = Q; ptr; ptr = ptr->next)
log(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time);
#endif IGMP_DEBUG
}