1 /* $NetBSD: callout.c,v 1.7 2003/03/05 21:05:38 wiz 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(void); 30 #else 31 #define print_Q() 32 #endif 33 34 int secs_remaining(int); 35 36 void 37 callout_init(void) 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(void) 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 logit(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 * delay: number of units for timeout 87 * action: function to be called on timeout 88 * data: what to call the timeout function with 89 */ 90 int 91 timer_setTimer(int delay, cfunc_t action, char *data) 92 { 93 struct timeout_q *ptr, *node, *prev; 94 95 if (in_callout) 96 return -1; 97 98 in_callout = 1; 99 100 /* create a node */ 101 node = (struct timeout_q *)malloc(sizeof(struct timeout_q)); 102 if (node == 0) { 103 logit(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n"); 104 in_callout = 0; 105 return -1; 106 } 107 node->func = action; 108 node->data = data; 109 node->time = delay; 110 node->next = 0; 111 node->id = ++id; 112 113 prev = ptr = Q; 114 115 /* insert node in the queue */ 116 117 /* if the queue is empty, insert the node and return */ 118 if (!Q) 119 Q = node; 120 else { 121 /* chase the pointer looking for the right place */ 122 while (ptr) { 123 124 if (delay < ptr->time) { 125 /* right place */ 126 127 node->next = ptr; 128 if (ptr == Q) 129 Q = node; 130 else 131 prev->next = node; 132 ptr->time -= node->time; 133 print_Q(); 134 in_callout = 0; 135 return node->id; 136 } else { 137 /* keep moving */ 138 139 delay -= ptr->time; node->time = delay; 140 prev = ptr; 141 ptr = ptr->next; 142 } 143 } 144 prev->next = node; 145 } 146 print_Q(); 147 in_callout = 0; 148 return node->id; 149 } 150 151 152 /* clears the associated timer */ 153 void 154 timer_clearTimer(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(void) 206 { 207 struct timeout_q *ptr; 208 209 for(ptr = Q; ptr; ptr = ptr->next) 210 logit(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time); 211 } 212 #endif /* IGMP_DEBUG */ 213 214 int 215 secs_remaining(int timer_id) 216 { 217 struct timeout_q *ptr; 218 int left=0; 219 220 for (ptr = Q; ptr && ptr->id != timer_id; ptr = ptr->next) 221 left += ptr->time; 222 223 if (!ptr) /* not found */ 224 return 0; 225 226 return left + ptr->time; 227 } 228