1 /* $NetBSD: schedule.c,v 1.4 2006/09/09 16:22:10 manu Exp $ */
2
3 /* $KAME: schedule.c,v 1.19 2001/11/05 10:53:19 sakane Exp $ */
4
5 /*
6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the project nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include "config.h"
35
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/time.h>
39 #include <sys/queue.h>
40 #include <sys/socket.h>
41
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <errno.h>
46 #include <time.h>
47
48 #include "misc.h"
49 #include "plog.h"
50 #include "schedule.h"
51 #include "var.h"
52 #include "gcmalloc.h"
53
54 #define FIXY2038PROBLEM
55
56 #ifndef TAILQ_FOREACH
57 #define TAILQ_FOREACH(elm, head, field) \
58 for (elm = TAILQ_FIRST(head); elm; elm = TAILQ_NEXT(elm, field))
59 #endif
60
61 static struct timeval timeout;
62
63 #ifdef FIXY2038PROBLEM
64 #define Y2038TIME_T 0x7fffffff
65 static time_t launched; /* time when the program launched. */
66 static time_t deltaY2038;
67 #endif
68
69 static TAILQ_HEAD(_schedtree, sched) sctree;
70
71 static void sched_add __P((struct sched *));
72 static time_t current_time __P((void));
73
74 /*
75 * schedule handler
76 * OUT:
77 * time to block until next event.
78 * if no entry, NULL returned.
79 */
80 struct timeval *
schedular()81 schedular()
82 {
83 time_t now, delta;
84 struct sched *p, *next = NULL;
85
86 now = current_time();
87
88 for (p = TAILQ_FIRST(&sctree); p; p = next) {
89 /* if the entry has been daed, remove it */
90 if (p->dead)
91 goto next_schedule;
92
93 /* if the time hasn't come, proceed to the next entry */
94 if (now < p->xtime) {
95 next = TAILQ_NEXT(p, chain);
96 continue;
97 }
98
99 /* mark it with dead. and call the function. */
100 p->dead = 1;
101 if (p->func != NULL)
102 (p->func)(p->param);
103
104 next_schedule:
105 next = TAILQ_NEXT(p, chain);
106 TAILQ_REMOVE(&sctree, p, chain);
107 racoon_free(p);
108 }
109
110 p = TAILQ_FIRST(&sctree);
111 if (p == NULL)
112 return NULL;
113
114 now = current_time();
115
116 delta = p->xtime - now;
117 timeout.tv_sec = delta < 0 ? 0 : delta;
118 timeout.tv_usec = 0;
119
120 return &timeout;
121 }
122
123 /*
124 * add new schedule to schedule table.
125 */
126 struct sched *
sched_new(tick,func,param)127 sched_new(tick, func, param)
128 time_t tick;
129 void (*func) __P((void *));
130 void *param;
131 {
132 static long id = 1;
133 struct sched *new;
134
135 new = (struct sched *)racoon_malloc(sizeof(*new));
136 if (new == NULL)
137 return NULL;
138
139 memset(new, 0, sizeof(*new));
140 new->func = func;
141 new->param = param;
142
143 new->id = id++;
144 time(&new->created);
145 new->tick = tick;
146
147 new->xtime = current_time() + tick;
148 new->dead = 0;
149
150 /* add to schedule table */
151 sched_add(new);
152
153 return(new);
154 }
155
156 /* add new schedule to schedule table */
157 static void
sched_add(sc)158 sched_add(sc)
159 struct sched *sc;
160 {
161 struct sched *p;
162
163 TAILQ_FOREACH(p, &sctree, chain) {
164 if (sc->xtime < p->xtime) {
165 TAILQ_INSERT_BEFORE(p, sc, chain);
166 return;
167 }
168 }
169 if (p == NULL)
170 TAILQ_INSERT_TAIL(&sctree, sc, chain);
171
172 return;
173 }
174
175 /* get current time.
176 * if defined FIXY2038PROBLEM, base time is the time when called sched_init().
177 * Otherwise, conform to time(3).
178 */
179 static time_t
current_time()180 current_time()
181 {
182 time_t n;
183 #ifdef FIXY2038PROBLEM
184 time_t t;
185
186 time(&n);
187 t = n - launched;
188 if (t < 0)
189 t += deltaY2038;
190
191 return t;
192 #else
193 return time(&n);
194 #endif
195 }
196
197 void
sched_kill(sc)198 sched_kill(sc)
199 struct sched *sc;
200 {
201 sc->dead = 1;
202
203 return;
204 }
205
206 /* XXX this function is probably unnecessary. */
207 void
sched_scrub_param(param)208 sched_scrub_param(param)
209 void *param;
210 {
211 struct sched *sc;
212
213 TAILQ_FOREACH(sc, &sctree, chain) {
214 if (sc->param == param) {
215 if (!sc->dead) {
216 plog(LLV_DEBUG, LOCATION, NULL,
217 "an undead schedule has been deleted.\n");
218 }
219 sched_kill(sc);
220 }
221 }
222 }
223
224 /*
225 * for debug
226 */
227 int
sched_dump(buf,len)228 sched_dump(buf, len)
229 caddr_t *buf;
230 int *len;
231 {
232 caddr_t new;
233 struct sched *p;
234 struct scheddump *dst;
235 int cnt = 0;
236
237 /* initialize */
238 *len = 0;
239 *buf = NULL;
240
241 TAILQ_FOREACH(p, &sctree, chain)
242 cnt++;
243
244 /* no entry */
245 if (cnt == 0)
246 return -1;
247
248 *len = cnt * sizeof(*dst);
249
250 new = racoon_malloc(*len);
251 if (new == NULL)
252 return -1;
253 dst = (struct scheddump *)new;
254
255 p = TAILQ_FIRST(&sctree);
256 while (p) {
257 dst->xtime = p->xtime;
258 dst->id = p->id;
259 dst->created = p->created;
260 dst->tick = p->tick;
261
262 p = TAILQ_NEXT(p, chain);
263 if (p == NULL)
264 break;
265 dst++;
266 }
267
268 *buf = new;
269
270 return 0;
271 }
272
273 /* initialize schedule table */
274 void
sched_init()275 sched_init()
276 {
277 #ifdef FIXY2038PROBLEM
278 time(&launched);
279
280 deltaY2038 = Y2038TIME_T - launched;
281 #endif
282
283 TAILQ_INIT(&sctree);
284
285 return;
286 }
287
288 #ifdef STEST
289 #include <sys/types.h>
290 #include <sys/time.h>
291 #include <unistd.h>
292 #include <err.h>
293
294 void
test(tick)295 test(tick)
296 int *tick;
297 {
298 printf("execute %d\n", *tick);
299 racoon_free(tick);
300 }
301
302 void
getstdin()303 getstdin()
304 {
305 int *tick;
306 char buf[16];
307
308 read(0, buf, sizeof(buf));
309 if (buf[0] == 'd') {
310 struct scheddump *scbuf, *p;
311 int len;
312 sched_dump((caddr_t *)&scbuf, &len);
313 if (scbuf == NULL)
314 return;
315 for (p = scbuf; len; p++) {
316 printf("xtime=%ld\n", p->xtime);
317 len -= sizeof(*p);
318 }
319 racoon_free(scbuf);
320 return;
321 }
322
323 tick = (int *)racoon_malloc(sizeof(*tick));
324 *tick = atoi(buf);
325 printf("new queue tick = %d\n", *tick);
326 sched_new(*tick, test, tick);
327 }
328
329 int
main()330 main()
331 {
332 static fd_set mask0;
333 int nfds = 0;
334 fd_set rfds;
335 struct timeval *timeout;
336 int error;
337
338 FD_ZERO(&mask0);
339 FD_SET(0, &mask0);
340 nfds = 1;
341
342 /* initialize */
343 sched_init();
344
345 while (1) {
346 rfds = mask0;
347
348 timeout = schedular();
349
350 error = select(nfds, &rfds, (fd_set *)0, (fd_set *)0, timeout);
351 if (error < 0) {
352 switch (errno) {
353 case EINTR: continue;
354 default:
355 err(1, "select");
356 }
357 /*NOTREACHED*/
358 }
359
360 if (FD_ISSET(0, &rfds))
361 getstdin();
362 }
363 }
364 #endif
365