Sync with NetBSD. Many fixes to include:
[dragonfly.git] / usr.sbin / mrouted / callout.c
blob3d0e99ff33ee945c5e4011723fcae280b123621f
1 /*
2 * The mrouted program is covered by the license in the accompanying file
3 * named "LICENSE". Use of the mrouted program represents acceptance of
4 * the terms and conditions listed in that file.
6 * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
7 * Leland Stanford Junior University.
10 * callout.c,v 3.8.4.8 1998/01/06 01:58:45 fenner Exp
12 * $FreeBSD: src/usr.sbin/mrouted/callout.c,v 1.12 1999/08/28 01:17:03 peter Exp $
13 * $DragonFly: src/usr.sbin/mrouted/callout.c,v 1.5 2005/12/05 00:58:50 swildner Exp $
16 #include "defs.h"
18 /* the code below implements a callout queue */
19 static int id = 0;
20 static struct timeout_q *Q = 0; /* pointer to the beginning of timeout queue */
22 struct timeout_q {
23 struct timeout_q *next; /* next event */
24 int id;
25 cfunc_t func; /* function to call */
26 void *data; /* func's data */
27 int time; /* time offset to next event*/
30 #ifdef IGMP_DEBUG
31 static void print_Q(void);
32 #else
33 #define print_Q()
34 #endif
36 void
37 callout_init(void)
39 Q = (struct timeout_q *) 0;
42 void
43 free_all_callouts(void)
45 struct timeout_q *p;
47 while (Q) {
48 p = Q;
49 Q = Q->next;
50 free(p);
56 * elapsed_time seconds have passed; perform all the events that should
57 * happen.
59 void
60 age_callout_queue(int elapsed_time)
62 struct timeout_q *ptr;
63 int i = 0;
65 for (ptr = Q; ptr; ptr = Q, i++) {
66 if (ptr->time > elapsed_time) {
67 ptr->time -= elapsed_time;
68 return;
69 } else {
70 elapsed_time -= ptr->time;
71 Q = Q->next;
72 IF_DEBUG(DEBUG_TIMEOUT)
73 log(LOG_DEBUG, 0, "about to call timeout %d (#%d)", ptr->id, i);
74 if (ptr->func)
75 ptr->func(ptr->data);
76 free(ptr);
82 * Return in how many seconds age_callout_queue() would like to be called.
83 * Return -1 if there are no events pending.
85 int
86 timer_nextTimer(void)
88 if (Q) {
89 if (Q->time < 0) {
90 log(LOG_WARNING, 0, "timer_nextTimer top of queue says %d",
91 Q->time);
92 return 0;
94 return Q->time;
96 return -1;
99 /*
100 * sets the timer
102 * delay - number of units for timeout
103 * action - function to be called on timeout
104 * data - what to call the timeout function with
107 timer_setTimer(int delay, cfunc_t action, void *data)
109 struct timeout_q *ptr, *node, *prev;
110 int i = 0;
112 /* create a node */
113 node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
114 if (node == 0) {
115 log(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n");
116 return -1;
118 node->func = action;
119 node->data = data;
120 node->time = delay;
121 node->next = 0;
122 node->id = ++id;
124 prev = ptr = Q;
126 /* insert node in the queue */
128 /* if the queue is empty, insert the node and return */
129 if (!Q)
130 Q = node;
131 else {
132 /* chase the pointer looking for the right place */
133 while (ptr) {
135 if (delay < ptr->time) {
136 /* right place */
138 node->next = ptr;
139 if (ptr == Q)
140 Q = node;
141 else
142 prev->next = node;
143 ptr->time -= node->time;
144 print_Q();
145 IF_DEBUG(DEBUG_TIMEOUT)
146 log(LOG_DEBUG, 0, "created timeout %d (#%d)", node->id, i);
147 return node->id;
148 } else {
149 /* keep moving */
151 delay -= ptr->time; node->time = delay;
152 prev = ptr;
153 ptr = ptr->next;
155 i++;
157 prev->next = node;
159 print_Q();
160 IF_DEBUG(DEBUG_TIMEOUT)
161 log(LOG_DEBUG, 0, "created timeout %d (#%d)", node->id, i);
162 return node->id;
165 /* returns the time until the timer is scheduled */
167 timer_leftTimer(int timer_id)
169 struct timeout_q *ptr;
170 int left = 0;
172 if (!timer_id)
173 return -1;
175 for (ptr = Q; ptr; ptr = ptr->next) {
176 left += ptr->time;
177 if (ptr->id == timer_id)
178 return left;
180 return -1;
183 /* clears the associated timer. Returns 1 if succeeded. */
185 timer_clearTimer(int timer_id)
187 struct timeout_q *ptr, *prev;
188 int i = 0;
190 if (!timer_id)
191 return 0;
193 prev = ptr = Q;
196 * find the right node, delete it. the subsequent node's time
197 * gets bumped up
200 print_Q();
201 while (ptr) {
202 if (ptr->id == timer_id) {
203 /* got the right node */
205 /* unlink it from the queue */
206 if (ptr == Q)
207 Q = Q->next;
208 else
209 prev->next = ptr->next;
211 /* increment next node if any */
212 if (ptr->next != 0)
213 (ptr->next)->time += ptr->time;
215 if (ptr->data)
216 free(ptr->data);
217 IF_DEBUG(DEBUG_TIMEOUT)
218 log(LOG_DEBUG, 0, "deleted timer %d (#%d)", ptr->id, i);
219 free(ptr);
220 print_Q();
221 return 1;
223 prev = ptr;
224 ptr = ptr->next;
225 i++;
227 IF_DEBUG(DEBUG_TIMEOUT)
228 log(LOG_DEBUG, 0, "failed to delete timer %d (#%d)", timer_id, i);
229 print_Q();
230 return 0;
233 #ifdef IGMP_DEBUG
235 * debugging utility
237 static void
238 print_Q(void)
240 struct timeout_q *ptr;
242 IF_DEBUG(DEBUG_TIMEOUT)
243 for (ptr = Q; ptr; ptr = ptr->next)
244 log(LOG_DEBUG, 0, "(%d,%d) ", ptr->id, ptr->time);
246 #endif /* IGMP_DEBUG */