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