• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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