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