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 */ 15static int id = 0; 16static struct timeout_q *Q = 0; /* pointer to the beginning of timeout queue */ 17 18static int in_callout = 0; 19 20struct 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 29static void print_Q(void); 30#else 31#define print_Q() 32#endif 33 34void 35callout_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 */ 44void 45age_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 */ 87int 88timer_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 */ 150void 151timer_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 */ 201static void 202print_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 211int 212secs_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