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