1 /* 2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (c) 1995-1999 by Internet Software Consortium 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * $Id: ev_timers.c,v 1.6 2005/04/27 04:56:36 sra Exp $ 18 */ 19 20 /* ev_timers.c - implement timers for the eventlib 21 * vix 09sep95 [initial] 22 */ 23 24 /* Import. */ 25 26 #include "port_before.h" 27 #ifndef _LIBC 28 #include "fd_setsize.h" 29 #endif 30 31 #include <errno.h> 32 33 #ifndef _LIBC 34 #include <isc/assertions.h> 35 #endif 36 #include "isc/eventlib.h" 37 #include "eventlib_p.h" 38 39 #include "port_after.h" 40 41 /* Constants. */ 42 43 #define MILLION 1000000 44 #define BILLION 1000000000 45 46 /* Forward. */ 47 #ifdef _LIBC 48 static int __evOptMonoTime; 49 #else 50 static int due_sooner(void *, void *); 51 static void set_index(void *, int); 52 static void free_timer(void *, void *); 53 static void print_timer(void *, void *); 54 static void idle_timeout(evContext, void *, struct timespec, struct timespec); 55 56 /* Private type. */ 57 58 typedef struct { 59 evTimerFunc func; 60 void * uap; 61 struct timespec lastTouched; 62 struct timespec max_idle; 63 evTimer * timer; 64 } idle_timer; 65 #endif 66 /* Public. */ 67 68 struct timespec 69 evConsTime(time_t sec, long nsec) { 70 struct timespec x; 71 72 x.tv_sec = sec; 73 x.tv_nsec = nsec; 74 return (x); 75 } 76 77 struct timespec 78 evAddTime(struct timespec addend1, struct timespec addend2) { 79 struct timespec x; 80 81 x.tv_sec = addend1.tv_sec + addend2.tv_sec; 82 x.tv_nsec = addend1.tv_nsec + addend2.tv_nsec; 83 if (x.tv_nsec >= BILLION) { 84 x.tv_sec++; 85 x.tv_nsec -= BILLION; 86 } 87 return (x); 88 } 89 90 struct timespec 91 evSubTime(struct timespec minuend, struct timespec subtrahend) { 92 struct timespec x; 93 94 x.tv_sec = minuend.tv_sec - subtrahend.tv_sec; 95 if (minuend.tv_nsec >= subtrahend.tv_nsec) 96 x.tv_nsec = minuend.tv_nsec - subtrahend.tv_nsec; 97 else { 98 x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec; 99 x.tv_sec--; 100 } 101 return (x); 102 } 103 104 int 105 evCmpTime(struct timespec a, struct timespec b) { 106 long x = a.tv_sec - b.tv_sec; 107 108 if (x == 0L) 109 x = a.tv_nsec - b.tv_nsec; 110 return (x < 0L ? (-1) : x > 0L ? (1) : (0)); 111 } 112 113 struct timespec 114 evNowTime(void) { 115 struct timeval now; 116 #ifdef CLOCK_REALTIME 117 struct timespec tsnow; 118 int m = CLOCK_REALTIME; 119 120 #ifdef CLOCK_MONOTONIC 121 if (__evOptMonoTime) 122 m = CLOCK_MONOTONIC; 123 #endif 124 if (clock_gettime(m, &tsnow) == 0) 125 return (tsnow); 126 #endif 127 if (gettimeofday(&now, NULL) < 0) 128 return (evConsTime(0, 0)); 129 return (evTimeSpec(now)); 130 } 131 132 struct timespec 133 evUTCTime(void) { 134 struct timeval now; 135 #ifdef CLOCK_REALTIME 136 struct timespec tsnow; 137 if (clock_gettime(CLOCK_REALTIME, &tsnow) == 0) 138 return (tsnow); 139 #endif 140 if (gettimeofday(&now, NULL) < 0) 141 return (evConsTime(0, 0)); 142 return (evTimeSpec(now)); 143 } 144 145 #ifndef _LIBC 146 struct timespec 147 evLastEventTime(evContext opaqueCtx) { 148 evContext_p *ctx = opaqueCtx.opaque; 149 150 return (ctx->lastEventTime); 151 } 152 #endif 153 154 struct timespec 155 evTimeSpec(struct timeval tv) { 156 struct timespec ts; 157 158 ts.tv_sec = tv.tv_sec; 159 ts.tv_nsec = tv.tv_usec * 1000; 160 return (ts); 161 } 162 #if !defined(USE_KQUEUE) || !defined(_LIBC) 163 struct timeval 164 evTimeVal(struct timespec ts) { 165 struct timeval tv; 166 167 tv.tv_sec = ts.tv_sec; 168 tv.tv_usec = ts.tv_nsec / 1000; 169 return (tv); 170 } 171 #endif 172 173 #ifndef _LIBC 174 int 175 evSetTimer(evContext opaqueCtx, 176 evTimerFunc func, 177 void *uap, 178 struct timespec due, 179 struct timespec inter, 180 evTimerID *opaqueID 181 ) { 182 evContext_p *ctx = opaqueCtx.opaque; 183 evTimer *id; 184 185 evPrintf(ctx, 1, 186 "evSetTimer(ctx %p, func %p, uap %p, due %ld.%09ld, inter %ld.%09ld)\n", 187 ctx, func, uap, 188 (long)due.tv_sec, due.tv_nsec, 189 (long)inter.tv_sec, inter.tv_nsec); 190 191 #ifdef __hpux 192 /* 193 * tv_sec and tv_nsec are unsigned. 194 */ 195 if (due.tv_nsec >= BILLION) 196 EV_ERR(EINVAL); 197 198 if (inter.tv_nsec >= BILLION) 199 EV_ERR(EINVAL); 200 #else 201 if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION) 202 EV_ERR(EINVAL); 203 204 if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION) 205 EV_ERR(EINVAL); 206 #endif 207 208 /* due={0,0} is a magic cookie meaning "now." */ 209 if (due.tv_sec == (time_t)0 && due.tv_nsec == 0L) 210 due = evNowTime(); 211 212 /* Allocate and fill. */ 213 OKNEW(id); 214 id->func = func; 215 id->uap = uap; 216 id->due = due; 217 id->inter = inter; 218 219 if (heap_insert(ctx->timers, id) < 0) 220 return (-1); 221 222 /* Remember the ID if the caller provided us a place for it. */ 223 if (opaqueID) 224 opaqueID->opaque = id; 225 226 if (ctx->debug > 7) { 227 evPrintf(ctx, 7, "timers after evSetTimer:\n"); 228 (void) heap_for_each(ctx->timers, print_timer, (void *)ctx); 229 } 230 231 return (0); 232 } 233 234 int 235 evClearTimer(evContext opaqueCtx, evTimerID id) { 236 evContext_p *ctx = opaqueCtx.opaque; 237 evTimer *del = id.opaque; 238 239 if (ctx->cur != NULL && 240 ctx->cur->type == Timer && 241 ctx->cur->u.timer.this == del) { 242 evPrintf(ctx, 8, "deferring delete of timer (executing)\n"); 243 /* 244 * Setting the interval to zero ensures that evDrop() will 245 * clean up the timer. 246 */ 247 del->inter = evConsTime(0, 0); 248 return (0); 249 } 250 251 if (heap_element(ctx->timers, del->index) != del) 252 EV_ERR(ENOENT); 253 254 if (heap_delete(ctx->timers, del->index) < 0) 255 return (-1); 256 FREE(del); 257 258 if (ctx->debug > 7) { 259 evPrintf(ctx, 7, "timers after evClearTimer:\n"); 260 (void) heap_for_each(ctx->timers, print_timer, (void *)ctx); 261 } 262 263 return (0); 264 } 265 266 int 267 evConfigTimer(evContext opaqueCtx, 268 evTimerID id, 269 const char *param, 270 int value 271 ) { 272 evContext_p *ctx = opaqueCtx.opaque; 273 evTimer *timer = id.opaque; 274 int result=0; 275 276 UNUSED(value); 277 278 if (heap_element(ctx->timers, timer->index) != timer) 279 EV_ERR(ENOENT); 280 281 if (strcmp(param, "rate") == 0) 282 timer->mode |= EV_TMR_RATE; 283 else if (strcmp(param, "interval") == 0) 284 timer->mode &= ~EV_TMR_RATE; 285 else 286 EV_ERR(EINVAL); 287 288 return (result); 289 } 290 291 int 292 evResetTimer(evContext opaqueCtx, 293 evTimerID id, 294 evTimerFunc func, 295 void *uap, 296 struct timespec due, 297 struct timespec inter 298 ) { 299 evContext_p *ctx = opaqueCtx.opaque; 300 evTimer *timer = id.opaque; 301 struct timespec old_due; 302 int result=0; 303 304 if (heap_element(ctx->timers, timer->index) != timer) 305 EV_ERR(ENOENT); 306 307 #ifdef __hpux 308 /* 309 * tv_sec and tv_nsec are unsigned. 310 */ 311 if (due.tv_nsec >= BILLION) 312 EV_ERR(EINVAL); 313 314 if (inter.tv_nsec >= BILLION) 315 EV_ERR(EINVAL); 316 #else 317 if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION) 318 EV_ERR(EINVAL); 319 320 if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION) 321 EV_ERR(EINVAL); 322 #endif 323 324 old_due = timer->due; 325 326 timer->func = func; 327 timer->uap = uap; 328 timer->due = due; 329 timer->inter = inter; 330 331 switch (evCmpTime(due, old_due)) { 332 case -1: 333 result = heap_increased(ctx->timers, timer->index); 334 break; 335 case 0: 336 result = 0; 337 break; 338 case 1: 339 result = heap_decreased(ctx->timers, timer->index); 340 break; 341 } 342 343 if (ctx->debug > 7) { 344 evPrintf(ctx, 7, "timers after evResetTimer:\n"); 345 (void) heap_for_each(ctx->timers, print_timer, (void *)ctx); 346 } 347 348 return (result); 349 } 350 351 int 352 evSetIdleTimer(evContext opaqueCtx, 353 evTimerFunc func, 354 void *uap, 355 struct timespec max_idle, 356 evTimerID *opaqueID 357 ) { 358 evContext_p *ctx = opaqueCtx.opaque; 359 idle_timer *tt; 360 361 /* Allocate and fill. */ 362 OKNEW(tt); 363 tt->func = func; 364 tt->uap = uap; 365 tt->lastTouched = ctx->lastEventTime; 366 tt->max_idle = max_idle; 367 368 if (evSetTimer(opaqueCtx, idle_timeout, tt, 369 evAddTime(ctx->lastEventTime, max_idle), 370 max_idle, opaqueID) < 0) { 371 FREE(tt); 372 return (-1); 373 } 374 375 tt->timer = opaqueID->opaque; 376 377 return (0); 378 } 379 380 int 381 evClearIdleTimer(evContext opaqueCtx, evTimerID id) { 382 evTimer *del = id.opaque; 383 idle_timer *tt = del->uap; 384 385 FREE(tt); 386 return (evClearTimer(opaqueCtx, id)); 387 } 388 389 int 390 evResetIdleTimer(evContext opaqueCtx, 391 evTimerID opaqueID, 392 evTimerFunc func, 393 void *uap, 394 struct timespec max_idle 395 ) { 396 evContext_p *ctx = opaqueCtx.opaque; 397 evTimer *timer = opaqueID.opaque; 398 idle_timer *tt = timer->uap; 399 400 tt->func = func; 401 tt->uap = uap; 402 tt->lastTouched = ctx->lastEventTime; 403 tt->max_idle = max_idle; 404 405 return (evResetTimer(opaqueCtx, opaqueID, idle_timeout, tt, 406 evAddTime(ctx->lastEventTime, max_idle), 407 max_idle)); 408 } 409 410 int 411 evTouchIdleTimer(evContext opaqueCtx, evTimerID id) { 412 evContext_p *ctx = opaqueCtx.opaque; 413 evTimer *t = id.opaque; 414 idle_timer *tt = t->uap; 415 416 tt->lastTouched = ctx->lastEventTime; 417 418 return (0); 419 } 420 421 /* Public to the rest of eventlib. */ 422 423 heap_context 424 evCreateTimers(const evContext_p *ctx) { 425 426 UNUSED(ctx); 427 428 return (heap_new(due_sooner, set_index, 2048)); 429 } 430 431 void 432 evDestroyTimers(const evContext_p *ctx) { 433 (void) heap_for_each(ctx->timers, free_timer, NULL); 434 (void) heap_free(ctx->timers); 435 } 436 437 /* Private. */ 438 439 static int 440 due_sooner(void *a, void *b) { 441 evTimer *a_timer, *b_timer; 442 443 a_timer = a; 444 b_timer = b; 445 return (evCmpTime(a_timer->due, b_timer->due) < 0); 446 } 447 448 static void 449 set_index(void *what, int index) { 450 evTimer *timer; 451 452 timer = what; 453 timer->index = index; 454 } 455 456 static void 457 free_timer(void *what, void *uap) { 458 evTimer *t = what; 459 460 UNUSED(uap); 461 462 FREE(t); 463 } 464 465 static void 466 print_timer(void *what, void *uap) { 467 evTimer *cur = what; 468 evContext_p *ctx = uap; 469 470 cur = what; 471 evPrintf(ctx, 7, 472 " func %p, uap %p, due %ld.%09ld, inter %ld.%09ld\n", 473 cur->func, cur->uap, 474 (long)cur->due.tv_sec, cur->due.tv_nsec, 475 (long)cur->inter.tv_sec, cur->inter.tv_nsec); 476 } 477 478 static void 479 idle_timeout(evContext opaqueCtx, 480 void *uap, 481 struct timespec due, 482 struct timespec inter 483 ) { 484 evContext_p *ctx = opaqueCtx.opaque; 485 idle_timer *this = uap; 486 struct timespec idle; 487 488 UNUSED(due); 489 UNUSED(inter); 490 491 idle = evSubTime(ctx->lastEventTime, this->lastTouched); 492 if (evCmpTime(idle, this->max_idle) >= 0) { 493 (this->func)(opaqueCtx, this->uap, this->timer->due, 494 this->max_idle); 495 /* 496 * Setting the interval to zero will cause the timer to 497 * be cleaned up in evDrop(). 498 */ 499 this->timer->inter = evConsTime(0, 0); 500 FREE(this); 501 } else { 502 /* evDrop() will reschedule the timer. */ 503 this->timer->inter = evSubTime(this->max_idle, idle); 504 } 505 } 506 #endif /* !_LIBC */ 507 508 /*! \file */ 509