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(void);
30 #else
31 #define print_Q()
32 #endif
33
34 void
callout_init(void)35 callout_init(void)
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
age_callout_queue(void)45 age_callout_queue(void)
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 logit(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 * delay number of units for timeout
84 * action function to be called on timeout
85 * data what to call the timeout function with
86 */
87 int
timer_setTimer(int delay,cfunc_t action,char * data)88 timer_setTimer(int delay, cfunc_t action, char *data)
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 = malloc(sizeof(struct timeout_q));
99 if (node == 0) {
100 logit(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
timer_clearTimer(int timer_id)151 timer_clearTimer(int timer_id)
152 {
153 struct timeout_q *ptr, *prev;
154
155 if (in_callout)
156 return;
157 if (!timer_id)
158 return;
159
160 in_callout = 1;
161
162 prev = ptr = Q;
163
164 /*
165 * find the right node, delete it. the subsequent node's time
166 * gets bumped up
167 */
168
169 print_Q();
170 while (ptr) {
171 if (ptr->id == timer_id) {
172 /* got the right node */
173
174 /* unlink it from the queue */
175 if (ptr == Q)
176 Q = Q->next;
177 else
178 prev->next = ptr->next;
179
180 /* increment next node if any */
181 if (ptr->next != 0)
182 (ptr->next)->time += ptr->time;
183
184 free(ptr->data);
185 free(ptr);
186 print_Q();
187 in_callout = 0;
188 return;
189 }
190 prev = ptr;
191 ptr = ptr->next;
192 }
193 print_Q();
194 in_callout = 0;
195 }
196
197 #ifdef IGMP_DEBUG
198 /*
199 * debugging utility
200 */
201 static void
print_Q(void)202 print_Q(void)
203 {
204 struct timeout_q *ptr;
205
206 for(ptr = Q; ptr; ptr = ptr->next)
207 logit(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time);
208 }
209 #endif /* IGMP_DEBUG */
210
211 int
secs_remaining(int timer_id)212 secs_remaining(int timer_id)
213 {
214 struct timeout_q *ptr;
215 int left=0;
216
217 for (ptr = Q; ptr && ptr->id != timer_id; ptr = ptr->next)
218 left += ptr->time;
219
220 if (!ptr) /* not found */
221 return 0;
222
223 return left + ptr->time;
224 }
225