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