xref: /netbsd/usr.sbin/mrouted/callout.c (revision c60d41a9)
1*c60d41a9Swiz /*	$NetBSD: callout.c,v 1.7 2003/03/05 21:05:38 wiz Exp $	*/
2*c60d41a9Swiz 
3*c60d41a9Swiz /*
4*c60d41a9Swiz  * The mrouted program is covered by the license in the accompanying file
5*c60d41a9Swiz  * named "LICENSE".  Use of the mrouted program represents acceptance of
6*c60d41a9Swiz  * the terms and conditions listed in that file.
7*c60d41a9Swiz  *
8*c60d41a9Swiz  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
9*c60d41a9Swiz  * Leland Stanford Junior University.
10*c60d41a9Swiz  */
11*c60d41a9Swiz 
12*c60d41a9Swiz #include "defs.h"
13*c60d41a9Swiz 
14*c60d41a9Swiz /* the code below implements a callout queue */
15*c60d41a9Swiz static int id = 0;
16*c60d41a9Swiz static struct timeout_q  *Q = 0; /* pointer to the beginning of timeout queue */
17*c60d41a9Swiz 
18*c60d41a9Swiz static int in_callout = 0;
19*c60d41a9Swiz 
20*c60d41a9Swiz struct timeout_q {
21*c60d41a9Swiz 	struct timeout_q *next;		/* next event */
22*c60d41a9Swiz 	int        	 id;
23*c60d41a9Swiz 	cfunc_t          func;    	/* function to call */
24*c60d41a9Swiz 	char	   	 *data;		/* func's data */
25*c60d41a9Swiz 	int            	 time;		/* time offset to next event*/
26*c60d41a9Swiz };
27*c60d41a9Swiz 
28*c60d41a9Swiz #ifdef IGMP_DEBUG
29*c60d41a9Swiz static void print_Q(void);
30*c60d41a9Swiz #else
31*c60d41a9Swiz #define	print_Q()
32*c60d41a9Swiz #endif
33*c60d41a9Swiz 
34*c60d41a9Swiz int secs_remaining(int);
35*c60d41a9Swiz 
36*c60d41a9Swiz void
callout_init(void)37*c60d41a9Swiz callout_init(void)
38*c60d41a9Swiz {
39*c60d41a9Swiz     Q = (struct timeout_q *) 0;
40*c60d41a9Swiz }
41*c60d41a9Swiz 
42*c60d41a9Swiz 
43*c60d41a9Swiz /*
44*c60d41a9Swiz  * signal handler for SIGALARM that is called once every second
45*c60d41a9Swiz  */
46*c60d41a9Swiz void
age_callout_queue(void)47*c60d41a9Swiz age_callout_queue(void)
48*c60d41a9Swiz {
49*c60d41a9Swiz     struct timeout_q *ptr;
50*c60d41a9Swiz 
51*c60d41a9Swiz     if (in_callout)
52*c60d41a9Swiz 	return;
53*c60d41a9Swiz 
54*c60d41a9Swiz     in_callout = 1;
55*c60d41a9Swiz     ptr = Q;
56*c60d41a9Swiz 
57*c60d41a9Swiz     while (ptr) {
58*c60d41a9Swiz 	if (!ptr->time) {
59*c60d41a9Swiz 	    /* timeout has happened */
60*c60d41a9Swiz 	    Q = Q->next;
61*c60d41a9Swiz 
62*c60d41a9Swiz 	    in_callout = 0;
63*c60d41a9Swiz 	    if (ptr->func)
64*c60d41a9Swiz 		ptr->func(ptr->data);
65*c60d41a9Swiz 	    in_callout = 1;
66*c60d41a9Swiz 
67*c60d41a9Swiz 	    free(ptr);
68*c60d41a9Swiz 	    ptr = Q;
69*c60d41a9Swiz 	}
70*c60d41a9Swiz 	else {
71*c60d41a9Swiz 	    ptr->time --;
72*c60d41a9Swiz #ifdef IGMP_DEBUG
73*c60d41a9Swiz 	    logit(LOG_DEBUG,0,"[callout, age_callout_queue] -- time (%d)", ptr->time);
74*c60d41a9Swiz #endif /* IGMP_DEBUG */
75*c60d41a9Swiz 	    in_callout = 0; return;
76*c60d41a9Swiz 	}
77*c60d41a9Swiz     }
78*c60d41a9Swiz     in_callout = 0;
79*c60d41a9Swiz     return;
80*c60d41a9Swiz }
81*c60d41a9Swiz 
82*c60d41a9Swiz 
83*c60d41a9Swiz /*
84*c60d41a9Swiz  * sets the timer
85*c60d41a9Swiz  *
86*c60d41a9Swiz  * delay: number of units for timeout
87*c60d41a9Swiz  * action: function to be called on timeout
88*c60d41a9Swiz  * data: what to call the timeout function with
89*c60d41a9Swiz  */
90*c60d41a9Swiz int
timer_setTimer(int delay,cfunc_t action,char * data)91*c60d41a9Swiz timer_setTimer(int delay, cfunc_t action, char *data)
92*c60d41a9Swiz {
93*c60d41a9Swiz     struct     timeout_q  *ptr, *node, *prev;
94*c60d41a9Swiz 
95*c60d41a9Swiz     if (in_callout)
96*c60d41a9Swiz 	return -1;
97*c60d41a9Swiz 
98*c60d41a9Swiz     in_callout = 1;
99*c60d41a9Swiz 
100*c60d41a9Swiz     /* create a node */
101*c60d41a9Swiz     node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
102*c60d41a9Swiz     if (node == 0) {
103*c60d41a9Swiz 	logit(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n");
104*c60d41a9Swiz 	in_callout = 0;
105*c60d41a9Swiz 	return -1;
106*c60d41a9Swiz     }
107*c60d41a9Swiz     node->func = action;
108*c60d41a9Swiz     node->data = data;
109*c60d41a9Swiz     node->time = delay;
110*c60d41a9Swiz     node->next = 0;
111*c60d41a9Swiz     node->id   = ++id;
112*c60d41a9Swiz 
113*c60d41a9Swiz     prev = ptr = Q;
114*c60d41a9Swiz 
115*c60d41a9Swiz     /* insert node in the queue */
116*c60d41a9Swiz 
117*c60d41a9Swiz     /* if the queue is empty, insert the node and return */
118*c60d41a9Swiz     if (!Q)
119*c60d41a9Swiz 	Q = node;
120*c60d41a9Swiz     else {
121*c60d41a9Swiz 	/* chase the pointer looking for the right place */
122*c60d41a9Swiz 	while (ptr) {
123*c60d41a9Swiz 
124*c60d41a9Swiz 	    if (delay < ptr->time) {
125*c60d41a9Swiz 		/* right place */
126*c60d41a9Swiz 
127*c60d41a9Swiz 		node->next = ptr;
128*c60d41a9Swiz 		if (ptr == Q)
129*c60d41a9Swiz 		    Q = node;
130*c60d41a9Swiz 		else
131*c60d41a9Swiz 		    prev->next = node;
132*c60d41a9Swiz 		ptr->time -= node->time;
133*c60d41a9Swiz 		print_Q();
134*c60d41a9Swiz 		in_callout = 0;
135*c60d41a9Swiz 		return node->id;
136*c60d41a9Swiz 	    } else  {
137*c60d41a9Swiz 		/* keep moving */
138*c60d41a9Swiz 
139*c60d41a9Swiz 		delay -= ptr->time; node->time = delay;
140*c60d41a9Swiz 		prev = ptr;
141*c60d41a9Swiz 		ptr = ptr->next;
142*c60d41a9Swiz 	    }
143*c60d41a9Swiz 	}
144*c60d41a9Swiz 	prev->next = node;
145*c60d41a9Swiz     }
146*c60d41a9Swiz     print_Q();
147*c60d41a9Swiz     in_callout = 0;
148*c60d41a9Swiz     return node->id;
149*c60d41a9Swiz }
150*c60d41a9Swiz 
151*c60d41a9Swiz 
152*c60d41a9Swiz /* clears the associated timer */
153*c60d41a9Swiz void
timer_clearTimer(int timer_id)154*c60d41a9Swiz timer_clearTimer(int timer_id)
155*c60d41a9Swiz {
156*c60d41a9Swiz     struct timeout_q  *ptr, *prev;
157*c60d41a9Swiz 
158*c60d41a9Swiz     if (in_callout)
159*c60d41a9Swiz         return;
160*c60d41a9Swiz     if (!timer_id)
161*c60d41a9Swiz 	return;
162*c60d41a9Swiz 
163*c60d41a9Swiz     in_callout = 1;
164*c60d41a9Swiz 
165*c60d41a9Swiz     prev = ptr = Q;
166*c60d41a9Swiz 
167*c60d41a9Swiz     /*
168*c60d41a9Swiz      * find the right node, delete it. the subsequent node's time
169*c60d41a9Swiz      * gets bumped up
170*c60d41a9Swiz      */
171*c60d41a9Swiz 
172*c60d41a9Swiz     print_Q();
173*c60d41a9Swiz     while (ptr) {
174*c60d41a9Swiz 	if (ptr->id == timer_id) {
175*c60d41a9Swiz 	    /* got the right node */
176*c60d41a9Swiz 
177*c60d41a9Swiz 	    /* unlink it from the queue */
178*c60d41a9Swiz 	    if (ptr == Q)
179*c60d41a9Swiz 		Q = Q->next;
180*c60d41a9Swiz 	    else
181*c60d41a9Swiz 		prev->next = ptr->next;
182*c60d41a9Swiz 
183*c60d41a9Swiz 	    /* increment next node if any */
184*c60d41a9Swiz 	    if (ptr->next != 0)
185*c60d41a9Swiz 		(ptr->next)->time += ptr->time;
186*c60d41a9Swiz 
187*c60d41a9Swiz 	    free(ptr->data);
188*c60d41a9Swiz 	    free(ptr);
189*c60d41a9Swiz 	    print_Q();
190*c60d41a9Swiz 	    in_callout = 0;
191*c60d41a9Swiz 	    return;
192*c60d41a9Swiz 	}
193*c60d41a9Swiz 	prev = ptr;
194*c60d41a9Swiz 	ptr = ptr->next;
195*c60d41a9Swiz     }
196*c60d41a9Swiz     print_Q();
197*c60d41a9Swiz     in_callout = 0;
198*c60d41a9Swiz }
199*c60d41a9Swiz 
200*c60d41a9Swiz #ifdef IGMP_DEBUG
201*c60d41a9Swiz /*
202*c60d41a9Swiz  * debugging utility
203*c60d41a9Swiz  */
204*c60d41a9Swiz static void
print_Q(void)205*c60d41a9Swiz print_Q(void)
206*c60d41a9Swiz {
207*c60d41a9Swiz     struct timeout_q  *ptr;
208*c60d41a9Swiz 
209*c60d41a9Swiz     for(ptr = Q; ptr; ptr = ptr->next)
210*c60d41a9Swiz 	logit(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time);
211*c60d41a9Swiz }
212*c60d41a9Swiz #endif /* IGMP_DEBUG */
213*c60d41a9Swiz 
214*c60d41a9Swiz int
secs_remaining(int timer_id)215*c60d41a9Swiz secs_remaining(int timer_id)
216*c60d41a9Swiz {
217*c60d41a9Swiz     struct timeout_q  *ptr;
218*c60d41a9Swiz     int left=0;
219*c60d41a9Swiz 
220*c60d41a9Swiz     for (ptr = Q; ptr && ptr->id != timer_id; ptr = ptr->next)
221*c60d41a9Swiz        left += ptr->time;
222*c60d41a9Swiz 
223*c60d41a9Swiz     if (!ptr) /* not found */
224*c60d41a9Swiz        return 0;
225*c60d41a9Swiz 
226*c60d41a9Swiz     return left + ptr->time;
227*c60d41a9Swiz }
228