callout.c revision 1.1 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 * $Id: callout.c,v 1.1 1995/06/01 02:25:47 mycroft Exp $
11 */
12
13 #include "defs.h"
14
15 /* the code below implements a callout queue */
16 static int id = 0;
17 static struct timeout_q *Q = 0; /* pointer to the beginning of timeout queue */
18
19 static int in_callout= 0;
20
21 typedef void (* cfunc_t)();
22
23 struct timeout_q {
24 struct timeout_q *next; /* next event */
25 int id;
26 cfunc_t func ; /* function to call */
27 char *data; /* func's data */
28 int time; /* time offset to next event*/
29 };
30
31 static void print_Q();
32
33 void callout_init()
34 {
35 Q = (struct timeout_q *) 0;
36 }
37
38
39 /*
40 * signal handler for SIGALARM that is called once every second
41 */
42 void age_callout_queue()
43 {
44 struct timeout_q *ptr;
45
46 if (in_callout)
47 return;
48
49 in_callout = 1;
50 ptr = Q;
51
52 while (ptr){
53 if (!ptr->time ) {
54 /* timeout has happened */
55 if(ptr->func)
56 ptr->func(ptr->data);
57 Q = Q->next;
58
59 free(ptr);
60 ptr = Q;
61 }
62 else {
63 ptr->time --;
64 #ifdef IGMP_DEBUG
65 log(LOG_DEBUG,0,"[callout, age_callout_queue] -- time (%d)", ptr->time);
66 #endif IGMP_DEBUG
67 in_callout = 0; return;
68 }
69 }
70 in_callout = 0;
71 return;
72 }
73
74
75 /*
76 * sets the timer
77 */
78 int timer_setTimer(delay, action, data)
79 int delay; /* number of units for timeout */
80 cfunc_t action; /* function to be called on timeout */
81 char *data; /* what to call the timeout function with */
82 {
83 struct timeout_q *ptr, *node, *prev;
84
85 if (in_callout)
86 return -1;
87
88 in_callout = 1;
89
90 /* create a node */
91 node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
92 if (node == 0) {
93 log(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n");
94 in_callout = 0;
95 return -1;
96 }
97 node->func = action;
98 node->data = data;
99 node->time = delay;
100 node->next = 0;
101 node->id = ++id;
102
103 prev = ptr = Q;
104
105 /* insert node in the queue */
106
107 /* if the queue is empty, insert the node and return */
108 if (!Q)
109 Q = node;
110 else {
111 /* chase the pointer looking for the right place */
112 while (ptr){
113
114 if (delay < ptr->time){
115 /* right place */
116
117 node->next = ptr;
118 if (ptr == Q)
119 Q = node;
120 else
121 prev->next = node;
122 ptr->time -= node->time;
123 print_Q();
124 in_callout = 0;
125 return node->id;
126 }
127 else {
128 /* keep moving */
129
130 delay -= ptr->time; node->time = delay;
131 prev = ptr;
132 ptr = ptr->next;
133 }
134 }
135 prev->next = node;
136 }
137 print_Q();
138 in_callout = 0;
139 return node->id;
140 }
141
142
143 /* clears the associated timer */
144 void timer_clearTimer( timer_id)
145 int timer_id;
146 {
147 struct timeout_q *ptr, *prev;
148
149 if (in_callout) return;
150 in_callout = 1;
151
152
153 if ( !timer_id ) {in_callout = 0; return;}
154
155 prev = ptr = Q;
156
157 /*
158 * find the right node, delete it. the subsequent node's time
159 * gets bumped up
160 */
161
162 print_Q();
163 while (ptr){
164 if (ptr->id == timer_id){
165 /* got the right node */
166
167 /* unlink it from the queue */
168 if ( ptr == Q)
169 Q = Q->next;
170 else
171 prev->next = ptr->next;
172
173 /* increment next node if any */
174 if (ptr->next != 0)
175 (ptr->next)->time += ptr->time;
176
177 free(ptr->data);
178 free(ptr);
179 print_Q();
180 in_callout = 0;
181 return;
182 }
183 prev = ptr;
184 ptr = ptr->next;
185 }
186 print_Q();
187 in_callout = 0;
188 }
189
190 /*
191 * debugging utility
192 */
193 static void print_Q()
194 {
195 #ifdef IGMP_DEBUG
196 struct timeout_q *ptr;
197
198 for(ptr = Q; ptr; ptr = ptr->next)
199 log(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time);
200 #endif IGMP_DEBUG
201 }
202
203