kernel - Handle spinlock indefinite wait edge case
[dragonfly.git] / usr.sbin / mrouted / callout.c
blobcd9d33305cd98d4437e00782fd2f644af858bec7
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 $
15 #include "defs.h"
17 /* the code below implements a callout queue */
18 static int id = 0;
19 static struct timeout_q *Q = NULL; /* pointer to the beginning of timeout queue */
21 struct timeout_q {
22 struct timeout_q *next; /* next event */
23 int id;
24 cfunc_t func; /* function to call */
25 void *data; /* func's data */
26 int time; /* time offset to next event*/
29 #ifdef IGMP_DEBUG
30 static void print_Q(void);
31 #else
32 #define print_Q()
33 #endif
35 void
36 callout_init(void)
38 Q = NULL;
41 void
42 free_all_callouts(void)
44 struct timeout_q *p;
46 while (Q) {
47 p = Q;
48 Q = Q->next;
49 free(p);
55 * elapsed_time seconds have passed; perform all the events that should
56 * happen.
58 void
59 age_callout_queue(int elapsed_time)
61 struct timeout_q *ptr;
62 int i = 0;
64 for (ptr = Q; ptr; ptr = Q, i++) {
65 if (ptr->time > elapsed_time) {
66 ptr->time -= elapsed_time;
67 return;
68 } else {
69 elapsed_time -= ptr->time;
70 Q = Q->next;
71 IF_DEBUG(DEBUG_TIMEOUT)
72 dolog(LOG_DEBUG, 0, "about to call timeout %d (#%d)", ptr->id, i);
73 if (ptr->func)
74 ptr->func(ptr->data);
75 free(ptr);
81 * Return in how many seconds age_callout_queue() would like to be called.
82 * Return -1 if there are no events pending.
84 int
85 timer_nextTimer(void)
87 if (Q) {
88 if (Q->time < 0) {
89 dolog(LOG_WARNING, 0, "timer_nextTimer top of queue says %d",
90 Q->time);
91 return 0;
93 return Q->time;
95 return -1;
99 * sets the timer
101 * delay - number of units for timeout
102 * action - function to be called on timeout
103 * data - what to call the timeout function with
106 timer_setTimer(int delay, cfunc_t action, void *data)
108 struct timeout_q *ptr, *node, *prev;
109 int i = 0;
111 /* create a node */
112 node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
113 if (node == NULL) {
114 dolog(LOG_WARNING, 0, "Malloc Failed in timer_setTimer\n");
115 return -1;
117 node->func = action;
118 node->data = data;
119 node->time = delay;
120 node->next = NULL;
121 node->id = ++id;
123 prev = ptr = Q;
125 /* insert node in the queue */
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) {
134 if (delay < ptr->time) {
135 /* right place */
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 dolog(LOG_DEBUG, 0, "created timeout %d (#%d)", node->id, i);
146 return node->id;
147 } else {
148 /* keep moving */
150 delay -= ptr->time; node->time = delay;
151 prev = ptr;
152 ptr = ptr->next;
154 i++;
156 prev->next = node;
158 print_Q();
159 IF_DEBUG(DEBUG_TIMEOUT)
160 dolog(LOG_DEBUG, 0, "created timeout %d (#%d)", node->id, i);
161 return node->id;
164 /* returns the time until the timer is scheduled */
166 timer_leftTimer(int timer_id)
168 struct timeout_q *ptr;
169 int left = 0;
171 if (!timer_id)
172 return -1;
174 for (ptr = Q; ptr; ptr = ptr->next) {
175 left += ptr->time;
176 if (ptr->id == timer_id)
177 return left;
179 return -1;
182 /* clears the associated timer. Returns 1 if succeeded. */
184 timer_clearTimer(int timer_id)
186 struct timeout_q *ptr, *prev;
187 int i = 0;
189 if (!timer_id)
190 return 0;
192 prev = ptr = Q;
195 * find the right node, delete it. the subsequent node's time
196 * gets bumped up
199 print_Q();
200 while (ptr) {
201 if (ptr->id == timer_id) {
202 /* got the right node */
204 /* unlink it from the queue */
205 if (ptr == Q)
206 Q = Q->next;
207 else
208 prev->next = ptr->next;
210 /* increment next node if any */
211 if (ptr->next != NULL)
212 (ptr->next)->time += ptr->time;
214 if (ptr->data)
215 free(ptr->data);
216 IF_DEBUG(DEBUG_TIMEOUT)
217 dolog(LOG_DEBUG, 0, "deleted timer %d (#%d)", ptr->id, i);
218 free(ptr);
219 print_Q();
220 return 1;
222 prev = ptr;
223 ptr = ptr->next;
224 i++;
226 IF_DEBUG(DEBUG_TIMEOUT)
227 dolog(LOG_DEBUG, 0, "failed to delete timer %d (#%d)", timer_id, i);
228 print_Q();
229 return 0;
232 #ifdef IGMP_DEBUG
234 * debugging utility
236 static void
237 print_Q(void)
239 struct timeout_q *ptr;
241 IF_DEBUG(DEBUG_TIMEOUT)
242 for (ptr = Q; ptr; ptr = ptr->next)
243 dolog(LOG_DEBUG, 0, "(%d,%d) ", ptr->id, ptr->time);
245 #endif /* IGMP_DEBUG */