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