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