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