callout.c revision 1.4 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