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