Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[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  * $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.2 2003/06/17 04:29:57 dillon Exp $
14  */
15
16 #include "defs.h"
17
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 */
21
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*/
28 };
29
30 #ifdef IGMP_DEBUG
31 static void print_Q __P((void));
32 #else
33 #define print_Q()       
34 #endif
35
36 void
37 callout_init()
38 {
39     Q = (struct timeout_q *) 0;
40 }
41
42 void
43 free_all_callouts()
44 {
45     struct timeout_q *p;
46
47     while (Q) {
48         p = Q;
49         Q = Q->next;
50         free(p);
51     }
52 }
53
54
55 /*
56  * elapsed_time seconds have passed; perform all the events that should
57  * happen.
58  */
59 void
60 age_callout_queue(elapsed_time)
61     int elapsed_time;
62 {
63     struct timeout_q *ptr;
64     int i = 0;
65
66     for (ptr = Q; ptr; ptr = Q, i++) {
67         if (ptr->time > elapsed_time) {
68             ptr->time -= elapsed_time;
69             return;
70         } else {
71             elapsed_time -= ptr->time;
72             Q = Q->next;
73             IF_DEBUG(DEBUG_TIMEOUT)
74             log(LOG_DEBUG, 0, "about to call timeout %d (#%d)", ptr->id, i);
75             if (ptr->func)
76                 ptr->func(ptr->data);
77             free(ptr);
78         }
79     }
80 }
81
82 /*
83  * Return in how many seconds age_callout_queue() would like to be called.
84  * Return -1 if there are no events pending.
85  */
86 int
87 timer_nextTimer()
88 {
89     if (Q) {
90         if (Q->time < 0) {
91             log(LOG_WARNING, 0, "timer_nextTimer top of queue says %d", 
92                         Q->time);
93             return 0;
94         }
95         return Q->time;
96     }
97     return -1;
98 }
99
100 /* 
101  * sets the timer
102  */
103 int
104 timer_setTimer(delay, action, data)
105     int         delay;          /* number of units for timeout */
106     cfunc_t     action;         /* function to be called on timeout */
107     void        *data;          /* what to call the timeout function with */
108 {
109     struct     timeout_q  *ptr, *node, *prev;
110     int i = 0;
111     
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;
117     }
118     node->func = action; 
119     node->data = data;
120     node->time = delay; 
121     node->next = 0;     
122     node->id   = ++id;
123     
124     prev = ptr = Q;
125     
126     /* insert node in the queue */
127     
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) {
134             
135             if (delay < ptr->time) {
136                 /* right place */
137                 
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 */
150                 
151                 delay -= ptr->time; node->time = delay;
152                 prev = ptr;
153                 ptr = ptr->next;
154             }
155             i++;
156         }
157         prev->next = node;
158     }
159     print_Q();
160     IF_DEBUG(DEBUG_TIMEOUT)
161     log(LOG_DEBUG, 0, "created timeout %d (#%d)", node->id, i);
162     return node->id;
163 }
164
165 /* returns the time until the timer is scheduled */
166 int
167 timer_leftTimer(timer_id)
168     int timer_id;
169 {
170     struct timeout_q *ptr;
171     int left = 0;
172
173     if (!timer_id)
174         return -1;
175
176     for (ptr = Q; ptr; ptr = ptr->next) {
177         left += ptr->time;
178         if (ptr->id == timer_id)
179             return left;
180     }
181     return -1;
182 }
183
184 /* clears the associated timer.  Returns 1 if succeeded. */
185 int
186 timer_clearTimer(timer_id)
187     int  timer_id;
188 {
189     struct timeout_q  *ptr, *prev;
190     int i = 0;
191     
192     if (!timer_id)
193         return 0;
194
195     prev = ptr = Q;
196     
197     /*
198      * find the right node, delete it. the subsequent node's time
199      * gets bumped up
200      */
201     
202     print_Q();
203     while (ptr) {
204         if (ptr->id == timer_id) {
205             /* got the right node */
206             
207             /* unlink it from the queue */
208             if (ptr == Q)
209                 Q = Q->next;
210             else
211                 prev->next = ptr->next;
212             
213             /* increment next node if any */
214             if (ptr->next != 0)
215                 (ptr->next)->time += ptr->time;
216             
217             if (ptr->data)
218                 free(ptr->data);
219             IF_DEBUG(DEBUG_TIMEOUT)
220             log(LOG_DEBUG, 0, "deleted timer %d (#%d)", ptr->id, i);
221             free(ptr);
222             print_Q();
223             return 1;
224         }
225         prev = ptr;
226         ptr = ptr->next;
227         i++;
228     }
229     IF_DEBUG(DEBUG_TIMEOUT)
230     log(LOG_DEBUG, 0, "failed to delete timer %d (#%d)", timer_id, i);
231     print_Q();
232     return 0;
233 }
234
235 #ifdef IGMP_DEBUG
236 /*
237  * debugging utility
238  */
239 static void
240 print_Q()
241 {
242     struct timeout_q  *ptr;
243     
244     IF_DEBUG(DEBUG_TIMEOUT)
245         for (ptr = Q; ptr; ptr = ptr->next)
246             log(LOG_DEBUG, 0, "(%d,%d) ", ptr->id, ptr->time);
247 }
248 #endif /* IGMP_DEBUG */