Home | History | Annotate | Download | only in racoon
      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 *
     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 *
    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
    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
    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
    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
    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
    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
    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
    295 test(tick)
    296 	int *tick;
    297 {
    298 	printf("execute %d\n", *tick);
    299 	racoon_free(tick);
    300 }
    301 
    302 void
    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
    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