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