Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.sbin / mrouted / callout.c
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.
5  *
6  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
7  * Leland Stanford Junior University.
8  *
9  *
10  * callout.c,v 3.8.4.8 1998/01/06 01:58:45 fenner Exp
11  */
12
13 #ifndef lint
14 static const char rcsid[] =
15   "$FreeBSD: src/usr.sbin/mrouted/callout.c,v 1.12 1999/08/28 01:17:03 peter Exp $";
16 #endif /* not lint */
17
18 #include "defs.h"
19
20 /* the code below implements a callout queue */
21 static int id = 0;
22 static struct timeout_q  *Q = 0; /* pointer to the beginning of timeout queue */
23
24 struct timeout_q {
25         struct timeout_q *next;         /* next event */
26         int              id;  
27         cfunc_t          func;          /* function to call */
28         void             *data;         /* func's data */
29         int              time;          /* time offset to next event*/
30 };
31
32 #ifdef IGMP_DEBUG
33 static void print_Q __P((void));
34 #else
35 #define print_Q()       
36 #endif
37
38 void
39 callout_init()
40 {
41     Q = (struct timeout_q *) 0;
42 }
43
44 void
45 free_all_callouts()
46 {
47     struct timeout_q *p;
48
49     while (Q) {
50         p = Q;
51         Q = Q->next;
52         free(p);
53     }
54 }
55
56
57 /*
58  * elapsed_time seconds have passed; perform all the events that should
59  * happen.
60  */
61 void
62 age_callout_queue(elapsed_time)
63     int elapsed_time;
64 {
65     struct timeout_q *ptr;
66     int i = 0;
67
68     for (ptr = Q; ptr; ptr = Q, i++) {
69         if (ptr->time > elapsed_time) {
70             ptr->time -= elapsed_time;
71             return;
72         } else {
73             elapsed_time -= ptr->time;
74             Q = Q->next;
75             IF_DEBUG(DEBUG_TIMEOUT)
76             log(LOG_DEBUG, 0, "about to call timeout %d (#%d)", ptr->id, i);
77             if (ptr->func)
78                 ptr->func(ptr->data);
79             free(ptr);
80         }
81     }
82 }
83
84 /*
85  * Return in how many seconds age_callout_queue() would like to be called.
86  * Return -1 if there are no events pending.
87  */
88 int
89 timer_nextTimer()
90 {
91     if (Q) {
92         if (Q->time < 0) {
93             log(LOG_WARNING, 0, "timer_nextTimer top of queue says %d", 
94                         Q->time);
95             return 0;
96         }
97         return Q->time;
98     }
99     return -1;
100 }
101
102 /* 
103  * sets the timer
104  */
105 int
106 timer_setTimer(delay, action, data)
107     int         delay;          /* number of units for timeout */
108     cfunc_t     action;         /* function to be called on timeout */
109     void        *data;          /* what to call the timeout function with */
110 {
111     struct     timeout_q  *ptr, *node, *prev;
112     int i = 0;
113     
114     /* create a node */ 
115     node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
116     if (node == 0) {
117         log(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n");
118         return -1;
119     }
120     node->func = action; 
121     node->data = data;
122     node->time = delay; 
123     node->next = 0;     
124     node->id   = ++id;
125     
126     prev = ptr = Q;
127     
128     /* insert node in the queue */
129     
130     /* if the queue is empty, insert the node and return */
131     if (!Q)
132         Q = node;
133     else {
134         /* chase the pointer looking for the right place */
135         while (ptr) {
136             
137             if (delay < ptr->time) {
138                 /* right place */
139                 
140                 node->next = ptr;
141                 if (ptr == Q)
142                     Q = node;
143                 else
144                     prev->next = node;
145                 ptr->time -= node->time;
146                 print_Q();
147                 IF_DEBUG(DEBUG_TIMEOUT)
148                 log(LOG_DEBUG, 0, "created timeout %d (#%d)", node->id, i);
149                 return node->id;
150             } else  {
151                 /* keep moving */
152                 
153                 delay -= ptr->time; node->time = delay;
154                 prev = ptr;
155                 ptr = ptr->next;
156             }
157             i++;
158         }
159         prev->next = node;
160     }
161     print_Q();
162     IF_DEBUG(DEBUG_TIMEOUT)
163     log(LOG_DEBUG, 0, "created timeout %d (#%d)", node->id, i);
164     return node->id;
165 }
166
167 /* returns the time until the timer is scheduled */
168 int
169 timer_leftTimer(timer_id)
170     int timer_id;
171 {
172     struct timeout_q *ptr;
173     int left = 0;
174
175     if (!timer_id)
176         return -1;
177
178     for (ptr = Q; ptr; ptr = ptr->next) {
179         left += ptr->time;
180         if (ptr->id == timer_id)
181             return left;
182     }
183     return -1;
184 }
185
186 /* clears the associated timer.  Returns 1 if succeeded. */
187 int
188 timer_clearTimer(timer_id)
189     int  timer_id;
190 {
191     struct timeout_q  *ptr, *prev;
192     int i = 0;
193     
194     if (!timer_id)
195         return 0;
196
197     prev = ptr = Q;
198     
199     /*
200      * find the right node, delete it. the subsequent node's time
201      * gets bumped up
202      */
203     
204     print_Q();
205     while (ptr) {
206         if (ptr->id == timer_id) {
207             /* got the right node */
208             
209             /* unlink it from the queue */
210             if (ptr == Q)
211                 Q = Q->next;
212             else
213                 prev->next = ptr->next;
214             
215             /* increment next node if any */
216             if (ptr->next != 0)
217                 (ptr->next)->time += ptr->time;
218             
219             if (ptr->data)
220                 free(ptr->data);
221             IF_DEBUG(DEBUG_TIMEOUT)
222             log(LOG_DEBUG, 0, "deleted timer %d (#%d)", ptr->id, i);
223             free(ptr);
224             print_Q();
225             return 1;
226         }
227         prev = ptr;
228         ptr = ptr->next;
229         i++;
230     }
231     IF_DEBUG(DEBUG_TIMEOUT)
232     log(LOG_DEBUG, 0, "failed to delete timer %d (#%d)", timer_id, i);
233     print_Q();
234     return 0;
235 }
236
237 #ifdef IGMP_DEBUG
238 /*
239  * debugging utility
240  */
241 static void
242 print_Q()
243 {
244     struct timeout_q  *ptr;
245     
246     IF_DEBUG(DEBUG_TIMEOUT)
247         for (ptr = Q; ptr; ptr = ptr->next)
248             log(LOG_DEBUG, 0, "(%d,%d) ", ptr->id, ptr->time);
249 }
250 #endif /* IGMP_DEBUG */