1 /* $NetBSD: schedule.c,v 1.7 2009/01/23 09:10:13 tteras 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 * Copyright (C) 2008 Timo Teras. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the project nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include "config.h" 36 37 #include <sys/types.h> 38 #include <sys/param.h> 39 #include <sys/time.h> 40 #include <sys/queue.h> 41 #include <sys/socket.h> 42 43 #include <stdlib.h> 44 #include <unistd.h> 45 #include <stdio.h> 46 #include <string.h> 47 #include <errno.h> 48 #include <time.h> 49 50 #include "misc.h" 51 #include "plog.h" 52 #include "schedule.h" 53 #include "var.h" 54 #include "gcmalloc.h" 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 TAILQ_HEAD(_schedtree, sched) sctree; 62 63 void 64 sched_get_monotonic_time(tv) 65 struct timeval *tv; 66 { 67 #ifdef HAVE_CLOCK_MONOTONIC 68 struct timespec ts; 69 70 clock_gettime(CLOCK_MONOTONIC, &ts); 71 tv->tv_sec = ts.tv_sec; 72 tv->tv_usec = ts.tv_nsec / 1000; 73 #else 74 gettimeofday(tv, NULL); 75 #endif 76 } 77 78 time_t 79 sched_monotonic_to_time_t(tv, now) 80 struct timeval *tv, *now; 81 { 82 #ifdef HAVE_CLOCK_MONOTONIC 83 struct timeval mynow, res; 84 85 if (now == NULL) { 86 sched_get_monotonic_time(&mynow); 87 now = &mynow; 88 } 89 timersub(now, tv, &res); 90 91 return time(NULL) + res.tv_sec; 92 #else 93 return tv->tv_sec; 94 #endif 95 } 96 97 /* 98 * schedule handler 99 * OUT: 100 * time to block until next event. 101 * if no entry, NULL returned. 102 */ 103 struct timeval * 104 schedular() 105 { 106 static struct timeval timeout; 107 struct timeval now; 108 struct sched *p; 109 110 sched_get_monotonic_time(&now); 111 while (!TAILQ_EMPTY(&sctree) && 112 timercmp(&TAILQ_FIRST(&sctree)->xtime, &now, <=)) { 113 void (*func)(struct sched *); 114 115 p = TAILQ_FIRST(&sctree); 116 func = p->func; 117 sched_cancel(p); 118 func(p); 119 } 120 121 p = TAILQ_FIRST(&sctree); 122 if (p == NULL) 123 return NULL; 124 125 timersub(&p->xtime, &now, &timeout); 126 127 return &timeout; 128 } 129 130 /* 131 * add new schedule to schedule table. 132 */ 133 void 134 sched_schedule(sc, tick, func) 135 struct sched *sc; 136 time_t tick; 137 void (*func) __P((struct sched *)); 138 { 139 static long id = 1; 140 struct sched *p; 141 struct timeval now; 142 143 sched_cancel(sc); 144 145 sc->func = func; 146 sc->id = id++; 147 sc->tick.tv_sec = tick; 148 sc->tick.tv_usec = 0; 149 sched_get_monotonic_time(&now); 150 timeradd(&now, &sc->tick, &sc->xtime); 151 152 /* add to schedule table */ 153 TAILQ_FOREACH(p, &sctree, chain) { 154 if (timercmp(&sc->xtime, &p->xtime, <)) 155 break; 156 } 157 if (p == NULL) 158 TAILQ_INSERT_TAIL(&sctree, sc, chain); 159 else 160 TAILQ_INSERT_BEFORE(p, sc, chain); 161 } 162 163 /* 164 * cancel scheduled callback 165 */ 166 void 167 sched_cancel(sc) 168 struct sched *sc; 169 { 170 if (sc->func != NULL) { 171 TAILQ_REMOVE(&sctree, sc, chain); 172 sc->func = NULL; 173 } 174 } 175 176 /* 177 * for debug 178 */ 179 int 180 sched_dump(buf, len) 181 caddr_t *buf; 182 int *len; 183 { 184 caddr_t new; 185 struct sched *p; 186 struct scheddump *dst; 187 struct timeval now, created; 188 int cnt = 0; 189 190 /* initialize */ 191 *len = 0; 192 *buf = NULL; 193 194 TAILQ_FOREACH(p, &sctree, chain) 195 cnt++; 196 197 /* no entry */ 198 if (cnt == 0) 199 return -1; 200 201 *len = cnt * sizeof(*dst); 202 203 new = racoon_malloc(*len); 204 if (new == NULL) 205 return -1; 206 dst = (struct scheddump *)new; 207 208 sched_get_monotonic_time(&now); 209 p = TAILQ_FIRST(&sctree); 210 while (p) { 211 timersub(&p->xtime, &p->tick, &created); 212 dst->xtime = p->xtime.tv_sec; 213 dst->id = p->id; 214 dst->created = sched_monotonic_to_time_t(&created, &now); 215 dst->tick = p->tick.tv_sec; 216 217 p = TAILQ_NEXT(p, chain); 218 if (p == NULL) 219 break; 220 dst++; 221 } 222 223 *buf = new; 224 225 return 0; 226 } 227 228 /* initialize schedule table */ 229 void 230 sched_init() 231 { 232 TAILQ_INIT(&sctree); 233 } 234 235 #ifdef STEST 236 #include <sys/types.h> 237 #include <sys/time.h> 238 #include <unistd.h> 239 #include <err.h> 240 241 void 242 test(tick) 243 int *tick; 244 { 245 printf("execute %d\n", *tick); 246 racoon_free(tick); 247 } 248 249 void 250 getstdin() 251 { 252 int *tick; 253 char buf[16]; 254 255 read(0, buf, sizeof(buf)); 256 if (buf[0] == 'd') { 257 struct scheddump *scbuf, *p; 258 int len; 259 sched_dump((caddr_t *)&scbuf, &len); 260 if (scbuf == NULL) 261 return; 262 for (p = scbuf; len; p++) { 263 printf("xtime=%ld\n", p->xtime); 264 len -= sizeof(*p); 265 } 266 racoon_free(scbuf); 267 return; 268 } 269 270 tick = (int *)racoon_malloc(sizeof(*tick)); 271 *tick = atoi(buf); 272 printf("new queue tick = %d\n", *tick); 273 sched_new(*tick, test, tick); 274 } 275 276 int 277 main() 278 { 279 static fd_set mask0; 280 int nfds = 0; 281 fd_set rfds; 282 struct timeval *timeout; 283 int error; 284 285 FD_ZERO(&mask0); 286 FD_SET(0, &mask0); 287 nfds = 1; 288 289 /* initialize */ 290 sched_init(); 291 292 while (1) { 293 rfds = mask0; 294 295 timeout = schedular(); 296 297 error = select(nfds, &rfds, (fd_set *)0, (fd_set *)0, timeout); 298 if (error < 0) { 299 switch (errno) { 300 case EINTR: continue; 301 default: 302 err(1, "select"); 303 } 304 /*NOTREACHED*/ 305 } 306 307 if (FD_ISSET(0, &rfds)) 308 getstdin(); 309 } 310 } 311 #endif 312