Rewrite the polling code. Instead of trying to do fancy polling enablement
[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.4 2003/11/22 11:38:13 eirikn 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(void);
32 #else
33 #define print_Q()       
34 #endif
35
36 void
37 callout_init(void)
38 {
39     Q = (struct timeout_q *) 0;
40 }
41
42 void
43 free_all_callouts(void)
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(int elapsed_time)
61 {
62     struct timeout_q *ptr;
63     int i = 0;
64
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);
77         }
78     }
79 }
80
81 /*
82  * Return in how many seconds age_callout_queue() would like to be called.
83  * Return -1 if there are no events pending.
84  */
85 int
86 timer_nextTimer(void)
87 {
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;
93         }
94         return Q->time;
95     }
96     return -1;
97 }
98
99 /* 
100  * sets the timer
101  */
102 int
103 timer_setTimer(delay, action, data)
104     int         delay;          /* number of units for timeout */
105     cfunc_t     action;         /* function to be called on timeout */
106     void        *data;          /* what to call the timeout function with */
107 {
108     struct     timeout_q  *ptr, *node, *prev;
109     int i = 0;
110     
111     /* create a node */ 
112     node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
113     if (node == 0) {
114         log(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n");
115         return -1;
116     }
117     node->func = action; 
118     node->data = data;
119     node->time = delay; 
120     node->next = 0;     
121     node->id   = ++id;
122     
123     prev = ptr = Q;
124     
125     /* insert node in the queue */
126     
127     /* if the queue is empty, insert the node and return */
128     if (!Q)
129         Q = node;
130     else {
131         /* chase the pointer looking for the right place */
132         while (ptr) {
133             
134             if (delay < ptr->time) {
135                 /* right place */
136                 
137                 node->next = ptr;
138                 if (ptr == Q)
139                     Q = node;
140                 else
141                     prev->next = node;
142                 ptr->time -= node->time;
143                 print_Q();
144                 IF_DEBUG(DEBUG_TIMEOUT)
145                 log(LOG_DEBUG, 0, "created timeout %d (#%d)", node->id, i);
146                 return node->id;
147             } else  {
148                 /* keep moving */
149                 
150                 delay -= ptr->time; node->time = delay;
151                 prev = ptr;
152                 ptr = ptr->next;
153             }
154             i++;
155         }
156         prev->next = node;
157     }
158     print_Q();
159     IF_DEBUG(DEBUG_TIMEOUT)
160     log(LOG_DEBUG, 0, "created timeout %d (#%d)", node->id, i);
161     return node->id;
162 }
163
164 /* returns the time until the timer is scheduled */
165 int
166 timer_leftTimer(timer_id)
167     int timer_id;
168 {
169     struct timeout_q *ptr;
170     int left = 0;
171
172     if (!timer_id)
173         return -1;
174
175     for (ptr = Q; ptr; ptr = ptr->next) {
176         left += ptr->time;
177         if (ptr->id == timer_id)
178             return left;
179     }
180     return -1;
181 }
182
183 /* clears the associated timer.  Returns 1 if succeeded. */
184 int
185 timer_clearTimer(timer_id)
186     int  timer_id;
187 {
188     struct timeout_q  *ptr, *prev;
189     int i = 0;
190     
191     if (!timer_id)
192         return 0;
193
194     prev = ptr = Q;
195     
196     /*
197      * find the right node, delete it. the subsequent node's time
198      * gets bumped up
199      */
200     
201     print_Q();
202     while (ptr) {
203         if (ptr->id == timer_id) {
204             /* got the right node */
205             
206             /* unlink it from the queue */
207             if (ptr == Q)
208                 Q = Q->next;
209             else
210                 prev->next = ptr->next;
211             
212             /* increment next node if any */
213             if (ptr->next != 0)
214                 (ptr->next)->time += ptr->time;
215             
216             if (ptr->data)
217                 free(ptr->data);
218             IF_DEBUG(DEBUG_TIMEOUT)
219             log(LOG_DEBUG, 0, "deleted timer %d (#%d)", ptr->id, i);
220             free(ptr);
221             print_Q();
222             return 1;
223         }
224         prev = ptr;
225         ptr = ptr->next;
226         i++;
227     }
228     IF_DEBUG(DEBUG_TIMEOUT)
229     log(LOG_DEBUG, 0, "failed to delete timer %d (#%d)", timer_id, i);
230     print_Q();
231     return 0;
232 }
233
234 #ifdef IGMP_DEBUG
235 /*
236  * debugging utility
237  */
238 static void
239 print_Q()
240 {
241     struct timeout_q  *ptr;
242     
243     IF_DEBUG(DEBUG_TIMEOUT)
244         for (ptr = Q; ptr; ptr = ptr->next)
245             log(LOG_DEBUG, 0, "(%d,%d) ", ptr->id, ptr->time);
246 }
247 #endif /* IGMP_DEBUG */