]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/rtadvd/timer.c
This commit was generated by cvs2svn to compensate for changes in r59901,
[FreeBSD/FreeBSD.git] / usr.sbin / rtadvd / timer.c
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  * $FreeBSD$
30  */
31
32 #include <sys/time.h>
33
34 #include <unistd.h>
35 #include <syslog.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #ifdef __NetBSD__
39 #include <search.h>
40 #endif
41 #include "timer.h"
42
43 static struct rtadvd_timer timer_head;
44
45 #define MILLION 1000000
46
47 static struct timeval tm_max = {0x7fffffff, 0x7fffffff};
48
49 void
50 rtadvd_timer_init()
51 {
52         memset(&timer_head, 0, sizeof(timer_head));
53
54         timer_head.next = timer_head.prev = &timer_head;
55         timer_head.tm = tm_max;
56 }
57
58 struct rtadvd_timer *
59 rtadvd_add_timer(void (*timeout) __P((void *)),
60                 void (*update) __P((void *, struct timeval *)),
61                  void *timeodata, void *updatedata)
62 {
63         struct rtadvd_timer *newtimer;
64
65         if ((newtimer = malloc(sizeof(*newtimer))) == NULL) {
66                 syslog(LOG_ERR,
67                        "<%s> can't allocate memory", __FUNCTION__);
68                 exit(1);
69         }
70
71         memset(newtimer, 0, sizeof(*newtimer));
72
73         if (timeout == NULL) {
74                 syslog(LOG_ERR,
75                        "<%s> timeout function unspecfied", __FUNCTION__);
76                 exit(1);
77         }
78         if (update == NULL) {
79                 syslog(LOG_ERR,
80                        "<%s> update function unspecfied", __FUNCTION__);
81                 exit(1);
82         }
83         newtimer->expire = timeout;
84         newtimer->update = update;
85         newtimer->expire_data = timeodata;
86         newtimer->update_data = updatedata;
87         newtimer->tm = tm_max;
88
89         /* link into chain */
90         insque(newtimer, &timer_head);
91
92         return(newtimer);
93 }
94
95 void
96 rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer)
97 {
98         struct timeval now;
99
100         /* reset the timer */
101         gettimeofday(&now, NULL);
102
103         TIMEVAL_ADD(&now, tm, &timer->tm);
104
105         /* update the next expiration time */
106         if (TIMEVAL_LT(timer->tm, timer_head.tm))
107                 timer_head.tm = timer->tm;
108
109         return;
110 }
111
112 /*
113  * Check expiration for each timer. If a timer is expired,
114  * call the expire function for the timer and update the timer.
115  * Return the next interval for select() call.
116  */
117 struct timeval *
118 rtadvd_check_timer()
119 {
120         static struct timeval returnval;
121         struct timeval now;
122         struct rtadvd_timer *tm = timer_head.next;
123
124         gettimeofday(&now, NULL);
125
126         timer_head.tm = tm_max;
127
128         while(tm != &timer_head) {
129                 if (TIMEVAL_LEQ(tm->tm, now)) {
130                         (*tm->expire)(tm->expire_data);
131                         (*tm->update)(tm->update_data, &tm->tm);
132                         TIMEVAL_ADD(&tm->tm, &now, &tm->tm);
133                 }
134
135                 if (TIMEVAL_LT(tm->tm, timer_head.tm))
136                         timer_head.tm = tm->tm;
137
138                 tm = tm->next;
139         }
140
141         if (TIMEVAL_LT(timer_head.tm, now)) {
142                 /* this may occur when the interval is too small */
143                 returnval.tv_sec = returnval.tv_usec = 0;
144         }
145         else
146                 TIMEVAL_SUB(&timer_head.tm, &now, &returnval);
147         return(&returnval);
148 }
149
150 struct timeval *
151 rtadvd_timer_rest(struct rtadvd_timer *timer)
152 {
153         static struct timeval returnval, now;
154
155         gettimeofday(&now, NULL);
156         if (TIMEVAL_LEQ(timer->tm, now)) {
157                 syslog(LOG_DEBUG,
158                        "<%s> a timer must be expired, but not yet",
159                        __FUNCTION__);
160                 returnval.tv_sec = returnval.tv_usec = 0;
161         }
162         else
163                 TIMEVAL_SUB(&timer->tm, &now, &returnval);
164
165         return(&returnval);
166 }
167
168 /* result = a + b */
169 void
170 TIMEVAL_ADD(struct timeval *a, struct timeval *b, struct timeval *result)
171 {
172         long l;
173
174         if ((l = a->tv_usec + b->tv_usec) < MILLION) {
175                 result->tv_usec = l;
176                 result->tv_sec = a->tv_sec + b->tv_sec;
177         }
178         else {
179                 result->tv_usec = l - MILLION;
180                 result->tv_sec = a->tv_sec + b->tv_sec + 1;
181         }
182 }
183
184 /*
185  * result = a - b
186  * XXX: this function assumes that a >= b.
187  */
188 void
189 TIMEVAL_SUB(struct timeval *a, struct timeval *b, struct timeval *result)
190 {
191         long l;
192
193         if ((l = a->tv_usec - b->tv_usec) >= 0) {
194                 result->tv_usec = l;
195                 result->tv_sec = a->tv_sec - b->tv_sec;
196         }
197         else {
198                 result->tv_usec = MILLION + l;
199                 result->tv_sec = a->tv_sec - b->tv_sec - 1;
200         }
201 }