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