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
61static struct timeval timeout;
62
63#ifdef FIXY2038PROBLEM
64#define Y2038TIME_T	0x7fffffff
65static time_t launched;		/* time when the program launched. */
66static time_t deltaY2038;
67#endif
68
69static TAILQ_HEAD(_schedtree, sched) sctree;
70
71static void sched_add __P((struct sched *));
72static 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 */
80struct timeval *
81schedular()
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 */
126struct sched *
127sched_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 */
157static void
158sched_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 */
179static time_t
180current_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
197void
198sched_kill(sc)
199	struct sched *sc;
200{
201	sc->dead = 1;
202
203	return;
204}
205
206/* XXX this function is probably unnecessary. */
207void
208sched_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 */
227int
228sched_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 */
274void
275sched_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
294void
295test(tick)
296	int *tick;
297{
298	printf("execute %d\n", *tick);
299	racoon_free(tick);
300}
301
302void
303getstdin()
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
329int
330main()
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