1 /* $KAME: timer.c,v 1.3 2000/05/22 22:23:07 itojun Exp $ */ 2 3 /* 4 * Copyright (C) 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $FreeBSD$ 32 */ 33 34 #include <sys/time.h> 35 36 #include <unistd.h> 37 #include <syslog.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #if defined(__NetBSD__) || defined(__OpenBSD__) 41 #include <search.h> 42 #endif 43 #include "timer.h" 44 45 static struct rtadvd_timer timer_head; 46 47 #define MILLION 1000000 48 #define TIMEVAL_EQUAL(t1,t2) ((t1)->tv_sec == (t2)->tv_sec &&\ 49 (t1)->tv_usec == (t2)->tv_usec) 50 51 static struct timeval tm_max = {0x7fffffff, 0x7fffffff}; 52 53 void 54 rtadvd_timer_init() 55 { 56 memset(&timer_head, 0, sizeof(timer_head)); 57 58 timer_head.next = timer_head.prev = &timer_head; 59 timer_head.tm = tm_max; 60 } 61 62 struct rtadvd_timer * 63 rtadvd_add_timer(void (*timeout) __P((void *)), 64 void (*update) __P((void *, struct timeval *)), 65 void *timeodata, void *updatedata) 66 { 67 struct rtadvd_timer *newtimer; 68 69 if ((newtimer = malloc(sizeof(*newtimer))) == NULL) { 70 syslog(LOG_ERR, 71 "<%s> can't allocate memory", __FUNCTION__); 72 exit(1); 73 } 74 75 memset(newtimer, 0, sizeof(*newtimer)); 76 77 if (timeout == NULL) { 78 syslog(LOG_ERR, 79 "<%s> timeout function unspecfied", __FUNCTION__); 80 exit(1); 81 } 82 if (update == NULL) { 83 syslog(LOG_ERR, 84 "<%s> update function unspecfied", __FUNCTION__); 85 exit(1); 86 } 87 newtimer->expire = timeout; 88 newtimer->update = update; 89 newtimer->expire_data = timeodata; 90 newtimer->update_data = updatedata; 91 newtimer->tm = tm_max; 92 93 /* link into chain */ 94 insque(newtimer, &timer_head); 95 96 return(newtimer); 97 } 98 99 void 100 rtadvd_remove_timer(struct rtadvd_timer **timer) 101 { 102 remque(*timer); 103 free(*timer); 104 *timer = NULL; 105 } 106 107 void 108 rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer) 109 { 110 struct timeval now; 111 112 /* reset the timer */ 113 gettimeofday(&now, NULL); 114 115 TIMEVAL_ADD(&now, tm, &timer->tm); 116 117 /* update the next expiration time */ 118 if (TIMEVAL_LT(timer->tm, timer_head.tm)) 119 timer_head.tm = timer->tm; 120 121 return; 122 } 123 124 /* 125 * Check expiration for each timer. If a timer is expired, 126 * call the expire function for the timer and update the timer. 127 * Return the next interval for select() call. 128 */ 129 struct timeval * 130 rtadvd_check_timer() 131 { 132 static struct timeval returnval; 133 struct timeval now; 134 struct rtadvd_timer *tm = timer_head.next; 135 136 gettimeofday(&now, NULL); 137 138 timer_head.tm = tm_max; 139 140 while(tm != &timer_head) { 141 if (TIMEVAL_LEQ(tm->tm, now)) { 142 (*tm->expire)(tm->expire_data); 143 (*tm->update)(tm->update_data, &tm->tm); 144 TIMEVAL_ADD(&tm->tm, &now, &tm->tm); 145 } 146 147 if (TIMEVAL_LT(tm->tm, timer_head.tm)) 148 timer_head.tm = tm->tm; 149 150 tm = tm->next; 151 } 152 153 if (TIMEVAL_EQUAL(&tm_max, &timer_head.tm)) { 154 /* no need to timeout */ 155 return(NULL); 156 } 157 else if (TIMEVAL_LT(timer_head.tm, now)) { 158 /* this may occur when the interval is too small */ 159 returnval.tv_sec = returnval.tv_usec = 0; 160 } 161 else 162 TIMEVAL_SUB(&timer_head.tm, &now, &returnval); 163 return(&returnval); 164 } 165 166 struct timeval * 167 rtadvd_timer_rest(struct rtadvd_timer *timer) 168 { 169 static struct timeval returnval, now; 170 171 gettimeofday(&now, NULL); 172 if (TIMEVAL_LEQ(timer->tm, now)) { 173 syslog(LOG_DEBUG, 174 "<%s> a timer must be expired, but not yet", 175 __FUNCTION__); 176 returnval.tv_sec = returnval.tv_usec = 0; 177 } 178 else 179 TIMEVAL_SUB(&timer->tm, &now, &returnval); 180 181 return(&returnval); 182 } 183 184 /* result = a + b */ 185 void 186 TIMEVAL_ADD(struct timeval *a, struct timeval *b, struct timeval *result) 187 { 188 long l; 189 190 if ((l = a->tv_usec + b->tv_usec) < MILLION) { 191 result->tv_usec = l; 192 result->tv_sec = a->tv_sec + b->tv_sec; 193 } 194 else { 195 result->tv_usec = l - MILLION; 196 result->tv_sec = a->tv_sec + b->tv_sec + 1; 197 } 198 } 199 200 /* 201 * result = a - b 202 * XXX: this function assumes that a >= b. 203 */ 204 void 205 TIMEVAL_SUB(struct timeval *a, struct timeval *b, struct timeval *result) 206 { 207 long l; 208 209 if ((l = a->tv_usec - b->tv_usec) >= 0) { 210 result->tv_usec = l; 211 result->tv_sec = a->tv_sec - b->tv_sec; 212 } 213 else { 214 result->tv_usec = MILLION + l; 215 result->tv_sec = a->tv_sec - b->tv_sec - 1; 216 } 217 } 218