xref: /netbsd-src/crypto/dist/ipsec-tools/src/racoon/schedule.c (revision 731a29e03b0c9acf8ca1c0d1c668a1af0f2796aa)
1*731a29e0Stteras /*	$NetBSD: schedule.c,v 1.7 2009/01/23 09:10:13 tteras Exp $	*/
28006965bSmanu 
3a8f0ad3cSmanu /*	$KAME: schedule.c,v 1.19 2001/11/05 10:53:19 sakane Exp $	*/
4a8f0ad3cSmanu 
5a8f0ad3cSmanu /*
6a8f0ad3cSmanu  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7fbf62026Stteras  * Copyright (C) 2008 Timo Teras.
8a8f0ad3cSmanu  * All rights reserved.
9a8f0ad3cSmanu  *
10a8f0ad3cSmanu  * Redistribution and use in source and binary forms, with or without
11a8f0ad3cSmanu  * modification, are permitted provided that the following conditions
12a8f0ad3cSmanu  * are met:
13a8f0ad3cSmanu  * 1. Redistributions of source code must retain the above copyright
14a8f0ad3cSmanu  *    notice, this list of conditions and the following disclaimer.
15a8f0ad3cSmanu  * 2. Redistributions in binary form must reproduce the above copyright
16a8f0ad3cSmanu  *    notice, this list of conditions and the following disclaimer in the
17a8f0ad3cSmanu  *    documentation and/or other materials provided with the distribution.
18a8f0ad3cSmanu  * 3. Neither the name of the project nor the names of its contributors
19a8f0ad3cSmanu  *    may be used to endorse or promote products derived from this software
20a8f0ad3cSmanu  *    without specific prior written permission.
21a8f0ad3cSmanu  *
22a8f0ad3cSmanu  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
23a8f0ad3cSmanu  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24a8f0ad3cSmanu  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25a8f0ad3cSmanu  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
26a8f0ad3cSmanu  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27a8f0ad3cSmanu  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28a8f0ad3cSmanu  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29a8f0ad3cSmanu  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30a8f0ad3cSmanu  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31a8f0ad3cSmanu  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32a8f0ad3cSmanu  * SUCH DAMAGE.
33a8f0ad3cSmanu  */
34a8f0ad3cSmanu 
35a8f0ad3cSmanu #include "config.h"
36a8f0ad3cSmanu 
37a8f0ad3cSmanu #include <sys/types.h>
38a8f0ad3cSmanu #include <sys/param.h>
39a8f0ad3cSmanu #include <sys/time.h>
40a8f0ad3cSmanu #include <sys/queue.h>
41a8f0ad3cSmanu #include <sys/socket.h>
42a8f0ad3cSmanu 
43a8f0ad3cSmanu #include <stdlib.h>
445d5e4e2fStteras #include <unistd.h>
45a8f0ad3cSmanu #include <stdio.h>
46a8f0ad3cSmanu #include <string.h>
47a8f0ad3cSmanu #include <errno.h>
48a8f0ad3cSmanu #include <time.h>
49a8f0ad3cSmanu 
50a8f0ad3cSmanu #include "misc.h"
51a8f0ad3cSmanu #include "plog.h"
52a8f0ad3cSmanu #include "schedule.h"
53a8f0ad3cSmanu #include "var.h"
54a8f0ad3cSmanu #include "gcmalloc.h"
55a8f0ad3cSmanu 
56a8f0ad3cSmanu #ifndef TAILQ_FOREACH
57a8f0ad3cSmanu #define TAILQ_FOREACH(elm, head, field) \
58a8f0ad3cSmanu         for (elm = TAILQ_FIRST(head); elm; elm = TAILQ_NEXT(elm, field))
59a8f0ad3cSmanu #endif
60a8f0ad3cSmanu 
61a8f0ad3cSmanu static TAILQ_HEAD(_schedtree, sched) sctree;
62a8f0ad3cSmanu 
635d5e4e2fStteras void
sched_get_monotonic_time(tv)645d5e4e2fStteras sched_get_monotonic_time(tv)
655d5e4e2fStteras 	struct timeval *tv;
665d5e4e2fStteras {
675d5e4e2fStteras #ifdef HAVE_CLOCK_MONOTONIC
685d5e4e2fStteras 	struct timespec ts;
695d5e4e2fStteras 
705d5e4e2fStteras 	clock_gettime(CLOCK_MONOTONIC, &ts);
715d5e4e2fStteras 	tv->tv_sec = ts.tv_sec;
725d5e4e2fStteras 	tv->tv_usec = ts.tv_nsec / 1000;
735d5e4e2fStteras #else
745d5e4e2fStteras 	gettimeofday(tv, NULL);
755d5e4e2fStteras #endif
765d5e4e2fStteras }
775d5e4e2fStteras 
785d5e4e2fStteras time_t
sched_monotonic_to_time_t(tv,now)795d5e4e2fStteras sched_monotonic_to_time_t(tv, now)
805d5e4e2fStteras 	struct timeval *tv, *now;
815d5e4e2fStteras {
825d5e4e2fStteras #ifdef HAVE_CLOCK_MONOTONIC
835d5e4e2fStteras 	struct timeval mynow, res;
845d5e4e2fStteras 
855d5e4e2fStteras 	if (now == NULL) {
865d5e4e2fStteras 		sched_get_monotonic_time(&mynow);
875d5e4e2fStteras 		now = &mynow;
885d5e4e2fStteras 	}
895d5e4e2fStteras 	timersub(now, tv, &res);
905d5e4e2fStteras 
915d5e4e2fStteras 	return time(NULL) + res.tv_sec;
925d5e4e2fStteras #else
935d5e4e2fStteras 	return tv->tv_sec;
945d5e4e2fStteras #endif
955d5e4e2fStteras }
96a8f0ad3cSmanu 
97a8f0ad3cSmanu /*
98a8f0ad3cSmanu  * schedule handler
99a8f0ad3cSmanu  * OUT:
100a8f0ad3cSmanu  *	time to block until next event.
101a8f0ad3cSmanu  *	if no entry, NULL returned.
102a8f0ad3cSmanu  */
103a8f0ad3cSmanu struct timeval *
schedular()104a8f0ad3cSmanu schedular()
105a8f0ad3cSmanu {
1065d5e4e2fStteras 	static struct timeval timeout;
1075d5e4e2fStteras 	struct timeval now;
108fbf62026Stteras 	struct sched *p;
109a8f0ad3cSmanu 
1105d5e4e2fStteras 	sched_get_monotonic_time(&now);
1115d5e4e2fStteras 	while (!TAILQ_EMPTY(&sctree) &&
1125d5e4e2fStteras 		timercmp(&TAILQ_FIRST(&sctree)->xtime, &now, <=)) {
113fbf62026Stteras 		void (*func)(struct sched *);
114a8f0ad3cSmanu 
115fbf62026Stteras 		p = TAILQ_FIRST(&sctree);
116fbf62026Stteras 		func = p->func;
117fbf62026Stteras 		sched_cancel(p);
118fbf62026Stteras 		func(p);
119a8f0ad3cSmanu 	}
120a8f0ad3cSmanu 
121a8f0ad3cSmanu 	p = TAILQ_FIRST(&sctree);
122a8f0ad3cSmanu 	if (p == NULL)
123a8f0ad3cSmanu 		return NULL;
124a8f0ad3cSmanu 
1255d5e4e2fStteras 	timersub(&p->xtime, &now, &timeout);
126a8f0ad3cSmanu 
127a8f0ad3cSmanu 	return &timeout;
128a8f0ad3cSmanu }
129a8f0ad3cSmanu 
130a8f0ad3cSmanu /*
131a8f0ad3cSmanu  * add new schedule to schedule table.
132a8f0ad3cSmanu  */
133fbf62026Stteras void
sched_schedule(sc,tick,func)134fbf62026Stteras sched_schedule(sc, tick, func)
135fbf62026Stteras 	struct sched *sc;
136a8f0ad3cSmanu 	time_t tick;
137fbf62026Stteras 	void (*func) __P((struct sched *));
138a8f0ad3cSmanu {
139a8f0ad3cSmanu 	static long id = 1;
140a8f0ad3cSmanu 	struct sched *p;
1415d5e4e2fStteras 	struct timeval now;
142a8f0ad3cSmanu 
143fbf62026Stteras 	sched_cancel(sc);
1445d5e4e2fStteras 
145fbf62026Stteras 	sc->func = func;
146fbf62026Stteras 	sc->id = id++;
1475d5e4e2fStteras 	sc->tick.tv_sec = tick;
1485d5e4e2fStteras 	sc->tick.tv_usec = 0;
1495d5e4e2fStteras 	sched_get_monotonic_time(&now);
1505d5e4e2fStteras 	timeradd(&now, &sc->tick, &sc->xtime);
151fbf62026Stteras 
152fbf62026Stteras 	/* add to schedule table */
153a8f0ad3cSmanu 	TAILQ_FOREACH(p, &sctree, chain) {
1545d5e4e2fStteras 		if (timercmp(&sc->xtime, &p->xtime, <))
155fbf62026Stteras 			break;
156a8f0ad3cSmanu 	}
157a8f0ad3cSmanu 	if (p == NULL)
158a8f0ad3cSmanu 		TAILQ_INSERT_TAIL(&sctree, sc, chain);
159fbf62026Stteras 	else
160fbf62026Stteras 		TAILQ_INSERT_BEFORE(p, sc, chain);
161a8f0ad3cSmanu }
162a8f0ad3cSmanu 
163fbf62026Stteras /*
164fbf62026Stteras  * cancel scheduled callback
165fbf62026Stteras  */
166fbf62026Stteras void
sched_cancel(sc)167fbf62026Stteras sched_cancel(sc)
168fbf62026Stteras 	struct sched *sc;
169fbf62026Stteras {
170fbf62026Stteras 	if (sc->func != NULL) {
171fbf62026Stteras 		TAILQ_REMOVE(&sctree, sc, chain);
172fbf62026Stteras 		sc->func = NULL;
173fbf62026Stteras 	}
174fbf62026Stteras }
175fbf62026Stteras 
176a8f0ad3cSmanu /*
177a8f0ad3cSmanu  * for debug
178a8f0ad3cSmanu  */
179a8f0ad3cSmanu int
sched_dump(buf,len)180a8f0ad3cSmanu sched_dump(buf, len)
181a8f0ad3cSmanu 	caddr_t *buf;
182a8f0ad3cSmanu 	int *len;
183a8f0ad3cSmanu {
184a8f0ad3cSmanu 	caddr_t new;
185a8f0ad3cSmanu 	struct sched *p;
186a8f0ad3cSmanu 	struct scheddump *dst;
1875d5e4e2fStteras 	struct timeval now, created;
188a8f0ad3cSmanu 	int cnt = 0;
189a8f0ad3cSmanu 
190a8f0ad3cSmanu 	/* initialize */
191a8f0ad3cSmanu 	*len = 0;
192a8f0ad3cSmanu 	*buf = NULL;
193a8f0ad3cSmanu 
194a8f0ad3cSmanu 	TAILQ_FOREACH(p, &sctree, chain)
195a8f0ad3cSmanu 		cnt++;
196a8f0ad3cSmanu 
197a8f0ad3cSmanu 	/* no entry */
198a8f0ad3cSmanu 	if (cnt == 0)
199a8f0ad3cSmanu 		return -1;
200a8f0ad3cSmanu 
201a8f0ad3cSmanu 	*len = cnt * sizeof(*dst);
202a8f0ad3cSmanu 
203a8f0ad3cSmanu 	new = racoon_malloc(*len);
204a8f0ad3cSmanu 	if (new == NULL)
205a8f0ad3cSmanu 		return -1;
206a8f0ad3cSmanu 	dst = (struct scheddump *)new;
207a8f0ad3cSmanu 
2085d5e4e2fStteras 	sched_get_monotonic_time(&now);
209a8f0ad3cSmanu 	p = TAILQ_FIRST(&sctree);
210a8f0ad3cSmanu 	while (p) {
2115d5e4e2fStteras 		timersub(&p->xtime, &p->tick, &created);
2125d5e4e2fStteras 		dst->xtime = p->xtime.tv_sec;
213a8f0ad3cSmanu 		dst->id = p->id;
2145d5e4e2fStteras 		dst->created = sched_monotonic_to_time_t(&created, &now);
2155d5e4e2fStteras 		dst->tick = p->tick.tv_sec;
216a8f0ad3cSmanu 
217a8f0ad3cSmanu 		p = TAILQ_NEXT(p, chain);
218a8f0ad3cSmanu 		if (p == NULL)
219a8f0ad3cSmanu 			break;
220a8f0ad3cSmanu 		dst++;
221a8f0ad3cSmanu 	}
222a8f0ad3cSmanu 
223a8f0ad3cSmanu 	*buf = new;
224a8f0ad3cSmanu 
225a8f0ad3cSmanu 	return 0;
226a8f0ad3cSmanu }
227a8f0ad3cSmanu 
228a8f0ad3cSmanu /* initialize schedule table */
229a8f0ad3cSmanu void
sched_init()230a8f0ad3cSmanu sched_init()
231a8f0ad3cSmanu {
232a8f0ad3cSmanu 	TAILQ_INIT(&sctree);
233a8f0ad3cSmanu }
234a8f0ad3cSmanu 
235a8f0ad3cSmanu #ifdef STEST
236a8f0ad3cSmanu #include <sys/types.h>
237a8f0ad3cSmanu #include <sys/time.h>
238a8f0ad3cSmanu #include <unistd.h>
239a8f0ad3cSmanu #include <err.h>
240a8f0ad3cSmanu 
241a8f0ad3cSmanu void
test(tick)242a8f0ad3cSmanu test(tick)
243a8f0ad3cSmanu 	int *tick;
244a8f0ad3cSmanu {
245a8f0ad3cSmanu 	printf("execute %d\n", *tick);
246a8f0ad3cSmanu 	racoon_free(tick);
247a8f0ad3cSmanu }
248a8f0ad3cSmanu 
249a8f0ad3cSmanu void
getstdin()250a8f0ad3cSmanu getstdin()
251a8f0ad3cSmanu {
252a8f0ad3cSmanu 	int *tick;
253a8f0ad3cSmanu 	char buf[16];
254a8f0ad3cSmanu 
255a8f0ad3cSmanu 	read(0, buf, sizeof(buf));
256a8f0ad3cSmanu 	if (buf[0] == 'd') {
257a8f0ad3cSmanu 		struct scheddump *scbuf, *p;
258a8f0ad3cSmanu 		int len;
259a8f0ad3cSmanu 		sched_dump((caddr_t *)&scbuf, &len);
260c8214a0aSmanu 		if (scbuf == NULL)
261a8f0ad3cSmanu 			return;
262a8f0ad3cSmanu 		for (p = scbuf; len; p++) {
263a8f0ad3cSmanu 			printf("xtime=%ld\n", p->xtime);
264a8f0ad3cSmanu 			len -= sizeof(*p);
265a8f0ad3cSmanu 		}
266a8f0ad3cSmanu 		racoon_free(scbuf);
267a8f0ad3cSmanu 		return;
268a8f0ad3cSmanu 	}
269a8f0ad3cSmanu 
270a8f0ad3cSmanu 	tick = (int *)racoon_malloc(sizeof(*tick));
271a8f0ad3cSmanu 	*tick = atoi(buf);
272a8f0ad3cSmanu 	printf("new queue tick = %d\n", *tick);
273a8f0ad3cSmanu 	sched_new(*tick, test, tick);
274a8f0ad3cSmanu }
275a8f0ad3cSmanu 
276a8f0ad3cSmanu int
main()277a8f0ad3cSmanu main()
278a8f0ad3cSmanu {
279a8f0ad3cSmanu 	static fd_set mask0;
280a8f0ad3cSmanu 	int nfds = 0;
281a8f0ad3cSmanu 	fd_set rfds;
282a8f0ad3cSmanu 	struct timeval *timeout;
283a8f0ad3cSmanu 	int error;
284a8f0ad3cSmanu 
285a8f0ad3cSmanu 	FD_ZERO(&mask0);
286a8f0ad3cSmanu 	FD_SET(0, &mask0);
287a8f0ad3cSmanu 	nfds = 1;
288a8f0ad3cSmanu 
289a8f0ad3cSmanu 	/* initialize */
290a8f0ad3cSmanu 	sched_init();
291a8f0ad3cSmanu 
292a8f0ad3cSmanu 	while (1) {
293a8f0ad3cSmanu 		rfds = mask0;
294a8f0ad3cSmanu 
295a8f0ad3cSmanu 		timeout = schedular();
296a8f0ad3cSmanu 
297a8f0ad3cSmanu 		error = select(nfds, &rfds, (fd_set *)0, (fd_set *)0, timeout);
298a8f0ad3cSmanu 		if (error < 0) {
299a8f0ad3cSmanu 			switch (errno) {
300a8f0ad3cSmanu 			case EINTR: continue;
301a8f0ad3cSmanu 			default:
302a8f0ad3cSmanu 				err(1, "select");
303a8f0ad3cSmanu 			}
304a8f0ad3cSmanu 			/*NOTREACHED*/
305a8f0ad3cSmanu 		}
306a8f0ad3cSmanu 
307a8f0ad3cSmanu 		if (FD_ISSET(0, &rfds))
308a8f0ad3cSmanu 			getstdin();
309a8f0ad3cSmanu 	}
310a8f0ad3cSmanu }
311a8f0ad3cSmanu #endif
312