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