ev_timers.c revision 156952
1156952Sume/* 2156952Sume * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 3156952Sume * Copyright (c) 1995-1999 by Internet Software Consortium 4156952Sume * 5156952Sume * Permission to use, copy, modify, and distribute this software for any 6156952Sume * purpose with or without fee is hereby granted, provided that the above 7156952Sume * copyright notice and this permission notice appear in all copies. 8156952Sume * 9156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10156952Sume * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11156952Sume * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12156952Sume * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13156952Sume * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14156952Sume * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15156952Sume * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16156952Sume */ 17156952Sume 18156952Sume/* ev_timers.c - implement timers for the eventlib 19156952Sume * vix 09sep95 [initial] 20156952Sume */ 21156952Sume 22156952Sume#if !defined(LINT) && !defined(CODECENTER) 23156952Sumestatic const char rcsid[] = "$Id: ev_timers.c,v 1.2.2.1.4.5 2004/03/17 02:39:13 marka Exp $"; 24156952Sume#endif 25156952Sume 26156952Sume/* Import. */ 27156952Sume 28156952Sume#include "port_before.h" 29156952Sume#include "fd_setsize.h" 30156952Sume 31156952Sume#include <errno.h> 32156952Sume 33156952Sume#include <isc/assertions.h> 34156952Sume#include <isc/eventlib.h> 35156952Sume#include "eventlib_p.h" 36156952Sume 37156952Sume#include "port_after.h" 38156952Sume 39156952Sume/* Constants. */ 40156952Sume 41156952Sume#define MILLION 1000000 42156952Sume#define BILLION 1000000000 43156952Sume 44156952Sume/* Forward. */ 45156952Sume 46156952Sumestatic int due_sooner(void *, void *); 47156952Sumestatic void set_index(void *, int); 48156952Sumestatic void free_timer(void *, void *); 49156952Sumestatic void print_timer(void *, void *); 50156952Sumestatic void idle_timeout(evContext, void *, struct timespec, struct timespec); 51156952Sume 52156952Sume/* Private type. */ 53156952Sume 54156952Sumetypedef struct { 55156952Sume evTimerFunc func; 56156952Sume void * uap; 57156952Sume struct timespec lastTouched; 58156952Sume struct timespec max_idle; 59156952Sume evTimer * timer; 60156952Sume} idle_timer; 61156952Sume 62156952Sume/* Public. */ 63156952Sume 64156952Sumestruct timespec 65156952SumeevConsTime(time_t sec, long nsec) { 66156952Sume struct timespec x; 67156952Sume 68156952Sume x.tv_sec = sec; 69156952Sume x.tv_nsec = nsec; 70156952Sume return (x); 71156952Sume} 72156952Sume 73156952Sumestruct timespec 74156952SumeevAddTime(struct timespec addend1, struct timespec addend2) { 75156952Sume struct timespec x; 76156952Sume 77156952Sume x.tv_sec = addend1.tv_sec + addend2.tv_sec; 78156952Sume x.tv_nsec = addend1.tv_nsec + addend2.tv_nsec; 79156952Sume if (x.tv_nsec >= BILLION) { 80156952Sume x.tv_sec++; 81156952Sume x.tv_nsec -= BILLION; 82156952Sume } 83156952Sume return (x); 84156952Sume} 85156952Sume 86156952Sumestruct timespec 87156952SumeevSubTime(struct timespec minuend, struct timespec subtrahend) { 88156952Sume struct timespec x; 89156952Sume 90156952Sume x.tv_sec = minuend.tv_sec - subtrahend.tv_sec; 91156952Sume if (minuend.tv_nsec >= subtrahend.tv_nsec) 92156952Sume x.tv_nsec = minuend.tv_nsec - subtrahend.tv_nsec; 93156952Sume else { 94156952Sume x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec; 95156952Sume x.tv_sec--; 96156952Sume } 97156952Sume return (x); 98156952Sume} 99156952Sume 100156952Sumeint 101156952SumeevCmpTime(struct timespec a, struct timespec b) { 102156952Sume long x = a.tv_sec - b.tv_sec; 103156952Sume 104156952Sume if (x == 0L) 105156952Sume x = a.tv_nsec - b.tv_nsec; 106156952Sume return (x < 0L ? (-1) : x > 0L ? (1) : (0)); 107156952Sume} 108156952Sume 109156952Sumestruct timespec 110156952SumeevNowTime() { 111156952Sume struct timeval now; 112156952Sume#ifdef CLOCK_REALTIME 113156952Sume struct timespec tsnow; 114156952Sume int m = CLOCK_REALTIME; 115156952Sume 116156952Sume#ifdef CLOCK_MONOTONIC 117156952Sume if (__evOptMonoTime) 118156952Sume m = CLOCK_MONOTONIC; 119156952Sume#endif 120156952Sume if (clock_gettime(m, &tsnow) == 0) 121156952Sume return (tsnow); 122156952Sume#endif 123156952Sume if (gettimeofday(&now, NULL) < 0) 124156952Sume return (evConsTime(0, 0)); 125156952Sume return (evTimeSpec(now)); 126156952Sume} 127156952Sume 128156952Sumestruct timespec 129156952SumeevUTCTime() { 130156952Sume struct timeval now; 131156952Sume#ifdef CLOCK_REALTIME 132156952Sume struct timespec tsnow; 133156952Sume if (clock_gettime(CLOCK_REALTIME, &tsnow) == 0) 134156952Sume return (tsnow); 135156952Sume#endif 136156952Sume if (gettimeofday(&now, NULL) < 0) 137156952Sume return (evConsTime(0, 0)); 138156952Sume return (evTimeSpec(now)); 139156952Sume} 140156952Sume 141156952Sumestruct timespec 142156952SumeevLastEventTime(evContext opaqueCtx) { 143156952Sume evContext_p *ctx = opaqueCtx.opaque; 144156952Sume 145156952Sume return (ctx->lastEventTime); 146156952Sume} 147156952Sume 148156952Sumestruct timespec 149156952SumeevTimeSpec(struct timeval tv) { 150156952Sume struct timespec ts; 151156952Sume 152156952Sume ts.tv_sec = tv.tv_sec; 153156952Sume ts.tv_nsec = tv.tv_usec * 1000; 154156952Sume return (ts); 155156952Sume} 156156952Sume 157156952Sumestruct timeval 158156952SumeevTimeVal(struct timespec ts) { 159156952Sume struct timeval tv; 160156952Sume 161156952Sume tv.tv_sec = ts.tv_sec; 162156952Sume tv.tv_usec = ts.tv_nsec / 1000; 163156952Sume return (tv); 164156952Sume} 165156952Sume 166156952Sumeint 167156952SumeevSetTimer(evContext opaqueCtx, 168156952Sume evTimerFunc func, 169156952Sume void *uap, 170156952Sume struct timespec due, 171156952Sume struct timespec inter, 172156952Sume evTimerID *opaqueID 173156952Sume) { 174156952Sume evContext_p *ctx = opaqueCtx.opaque; 175156952Sume evTimer *id; 176156952Sume 177156952Sume evPrintf(ctx, 1, 178156952Sume"evSetTimer(ctx %p, func %p, uap %p, due %ld.%09ld, inter %ld.%09ld)\n", 179156952Sume ctx, func, uap, 180156952Sume (long)due.tv_sec, due.tv_nsec, 181156952Sume (long)inter.tv_sec, inter.tv_nsec); 182156952Sume 183156952Sume#ifdef __hpux 184156952Sume /* 185156952Sume * tv_sec and tv_nsec are unsigned. 186156952Sume */ 187156952Sume if (due.tv_nsec >= BILLION) 188156952Sume EV_ERR(EINVAL); 189156952Sume 190156952Sume if (inter.tv_nsec >= BILLION) 191156952Sume EV_ERR(EINVAL); 192156952Sume#else 193156952Sume if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION) 194156952Sume EV_ERR(EINVAL); 195156952Sume 196156952Sume if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION) 197156952Sume EV_ERR(EINVAL); 198156952Sume#endif 199156952Sume 200156952Sume /* due={0,0} is a magic cookie meaning "now." */ 201156952Sume if (due.tv_sec == (time_t)0 && due.tv_nsec == 0L) 202156952Sume due = evNowTime(); 203156952Sume 204156952Sume /* Allocate and fill. */ 205156952Sume OKNEW(id); 206156952Sume id->func = func; 207156952Sume id->uap = uap; 208156952Sume id->due = due; 209156952Sume id->inter = inter; 210156952Sume 211156952Sume if (heap_insert(ctx->timers, id) < 0) 212156952Sume return (-1); 213156952Sume 214156952Sume /* Remember the ID if the caller provided us a place for it. */ 215156952Sume if (opaqueID) 216156952Sume opaqueID->opaque = id; 217156952Sume 218156952Sume if (ctx->debug > 7) { 219156952Sume evPrintf(ctx, 7, "timers after evSetTimer:\n"); 220156952Sume (void) heap_for_each(ctx->timers, print_timer, (void *)ctx); 221156952Sume } 222156952Sume 223156952Sume return (0); 224156952Sume} 225156952Sume 226156952Sumeint 227156952SumeevClearTimer(evContext opaqueCtx, evTimerID id) { 228156952Sume evContext_p *ctx = opaqueCtx.opaque; 229156952Sume evTimer *del = id.opaque; 230156952Sume 231156952Sume if (ctx->cur != NULL && 232156952Sume ctx->cur->type == Timer && 233156952Sume ctx->cur->u.timer.this == del) { 234156952Sume evPrintf(ctx, 8, "deferring delete of timer (executing)\n"); 235156952Sume /* 236156952Sume * Setting the interval to zero ensures that evDrop() will 237156952Sume * clean up the timer. 238156952Sume */ 239156952Sume del->inter = evConsTime(0, 0); 240156952Sume return (0); 241156952Sume } 242156952Sume 243156952Sume if (heap_element(ctx->timers, del->index) != del) 244156952Sume EV_ERR(ENOENT); 245156952Sume 246156952Sume if (heap_delete(ctx->timers, del->index) < 0) 247156952Sume return (-1); 248156952Sume FREE(del); 249156952Sume 250156952Sume if (ctx->debug > 7) { 251156952Sume evPrintf(ctx, 7, "timers after evClearTimer:\n"); 252156952Sume (void) heap_for_each(ctx->timers, print_timer, (void *)ctx); 253156952Sume } 254156952Sume 255156952Sume return (0); 256156952Sume} 257156952Sume 258156952Sumeint 259156952SumeevConfigTimer(evContext opaqueCtx, 260156952Sume evTimerID id, 261156952Sume const char *param, 262156952Sume int value 263156952Sume) { 264156952Sume evContext_p *ctx = opaqueCtx.opaque; 265156952Sume evTimer *timer = id.opaque; 266156952Sume int result=0; 267156952Sume 268156952Sume UNUSED(value); 269156952Sume 270156952Sume if (heap_element(ctx->timers, timer->index) != timer) 271156952Sume EV_ERR(ENOENT); 272156952Sume 273156952Sume if (strcmp(param, "rate") == 0) 274156952Sume timer->mode |= EV_TMR_RATE; 275156952Sume else if (strcmp(param, "interval") == 0) 276156952Sume timer->mode &= ~EV_TMR_RATE; 277156952Sume else 278156952Sume EV_ERR(EINVAL); 279156952Sume 280156952Sume return (result); 281156952Sume} 282156952Sume 283156952Sumeint 284156952SumeevResetTimer(evContext opaqueCtx, 285156952Sume evTimerID id, 286156952Sume evTimerFunc func, 287156952Sume void *uap, 288156952Sume struct timespec due, 289156952Sume struct timespec inter 290156952Sume) { 291156952Sume evContext_p *ctx = opaqueCtx.opaque; 292156952Sume evTimer *timer = id.opaque; 293156952Sume struct timespec old_due; 294156952Sume int result=0; 295156952Sume 296156952Sume if (heap_element(ctx->timers, timer->index) != timer) 297156952Sume EV_ERR(ENOENT); 298156952Sume 299156952Sume#ifdef __hpux 300156952Sume /* 301156952Sume * tv_sec and tv_nsec are unsigned. 302156952Sume */ 303156952Sume if (due.tv_nsec >= BILLION) 304156952Sume EV_ERR(EINVAL); 305156952Sume 306156952Sume if (inter.tv_nsec >= BILLION) 307156952Sume EV_ERR(EINVAL); 308156952Sume#else 309156952Sume if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION) 310156952Sume EV_ERR(EINVAL); 311156952Sume 312156952Sume if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION) 313156952Sume EV_ERR(EINVAL); 314156952Sume#endif 315156952Sume 316156952Sume old_due = timer->due; 317156952Sume 318156952Sume timer->func = func; 319156952Sume timer->uap = uap; 320156952Sume timer->due = due; 321156952Sume timer->inter = inter; 322156952Sume 323156952Sume switch (evCmpTime(due, old_due)) { 324156952Sume case -1: 325156952Sume result = heap_increased(ctx->timers, timer->index); 326156952Sume break; 327156952Sume case 0: 328156952Sume result = 0; 329156952Sume break; 330156952Sume case 1: 331156952Sume result = heap_decreased(ctx->timers, timer->index); 332156952Sume break; 333156952Sume } 334156952Sume 335156952Sume if (ctx->debug > 7) { 336156952Sume evPrintf(ctx, 7, "timers after evResetTimer:\n"); 337156952Sume (void) heap_for_each(ctx->timers, print_timer, (void *)ctx); 338156952Sume } 339156952Sume 340156952Sume return (result); 341156952Sume} 342156952Sume 343156952Sumeint 344156952SumeevSetIdleTimer(evContext opaqueCtx, 345156952Sume evTimerFunc func, 346156952Sume void *uap, 347156952Sume struct timespec max_idle, 348156952Sume evTimerID *opaqueID 349156952Sume) { 350156952Sume evContext_p *ctx = opaqueCtx.opaque; 351156952Sume idle_timer *tt; 352156952Sume 353156952Sume /* Allocate and fill. */ 354156952Sume OKNEW(tt); 355156952Sume tt->func = func; 356156952Sume tt->uap = uap; 357156952Sume tt->lastTouched = ctx->lastEventTime; 358156952Sume tt->max_idle = max_idle; 359156952Sume 360156952Sume if (evSetTimer(opaqueCtx, idle_timeout, tt, 361156952Sume evAddTime(ctx->lastEventTime, max_idle), 362156952Sume max_idle, opaqueID) < 0) { 363156952Sume FREE(tt); 364156952Sume return (-1); 365156952Sume } 366156952Sume 367156952Sume tt->timer = opaqueID->opaque; 368156952Sume 369156952Sume return (0); 370156952Sume} 371156952Sume 372156952Sumeint 373156952SumeevClearIdleTimer(evContext opaqueCtx, evTimerID id) { 374156952Sume evTimer *del = id.opaque; 375156952Sume idle_timer *tt = del->uap; 376156952Sume 377156952Sume FREE(tt); 378156952Sume return (evClearTimer(opaqueCtx, id)); 379156952Sume} 380156952Sume 381156952Sumeint 382156952SumeevResetIdleTimer(evContext opaqueCtx, 383156952Sume evTimerID opaqueID, 384156952Sume evTimerFunc func, 385156952Sume void *uap, 386156952Sume struct timespec max_idle 387156952Sume) { 388156952Sume evContext_p *ctx = opaqueCtx.opaque; 389156952Sume evTimer *timer = opaqueID.opaque; 390156952Sume idle_timer *tt = timer->uap; 391156952Sume 392156952Sume tt->func = func; 393156952Sume tt->uap = uap; 394156952Sume tt->lastTouched = ctx->lastEventTime; 395156952Sume tt->max_idle = max_idle; 396156952Sume 397156952Sume return (evResetTimer(opaqueCtx, opaqueID, idle_timeout, tt, 398156952Sume evAddTime(ctx->lastEventTime, max_idle), 399156952Sume max_idle)); 400156952Sume} 401156952Sume 402156952Sumeint 403156952SumeevTouchIdleTimer(evContext opaqueCtx, evTimerID id) { 404156952Sume evContext_p *ctx = opaqueCtx.opaque; 405156952Sume evTimer *t = id.opaque; 406156952Sume idle_timer *tt = t->uap; 407156952Sume 408156952Sume tt->lastTouched = ctx->lastEventTime; 409156952Sume 410156952Sume return (0); 411156952Sume} 412156952Sume 413156952Sume/* Public to the rest of eventlib. */ 414156952Sume 415156952Sumeheap_context 416156952SumeevCreateTimers(const evContext_p *ctx) { 417156952Sume 418156952Sume UNUSED(ctx); 419156952Sume 420156952Sume return (heap_new(due_sooner, set_index, 2048)); 421156952Sume} 422156952Sume 423156952Sumevoid 424156952SumeevDestroyTimers(const evContext_p *ctx) { 425156952Sume (void) heap_for_each(ctx->timers, free_timer, NULL); 426156952Sume (void) heap_free(ctx->timers); 427156952Sume} 428156952Sume 429156952Sume/* Private. */ 430156952Sume 431156952Sumestatic int 432156952Sumedue_sooner(void *a, void *b) { 433156952Sume evTimer *a_timer, *b_timer; 434156952Sume 435156952Sume a_timer = a; 436156952Sume b_timer = b; 437156952Sume return (evCmpTime(a_timer->due, b_timer->due) < 0); 438156952Sume} 439156952Sume 440156952Sumestatic void 441156952Sumeset_index(void *what, int index) { 442156952Sume evTimer *timer; 443156952Sume 444156952Sume timer = what; 445156952Sume timer->index = index; 446156952Sume} 447156952Sume 448156952Sumestatic void 449156952Sumefree_timer(void *what, void *uap) { 450156952Sume evTimer *t = what; 451156952Sume 452156952Sume UNUSED(uap); 453156952Sume 454156952Sume FREE(t); 455156952Sume} 456156952Sume 457156952Sumestatic void 458156952Sumeprint_timer(void *what, void *uap) { 459156952Sume evTimer *cur = what; 460156952Sume evContext_p *ctx = uap; 461156952Sume 462156952Sume cur = what; 463156952Sume evPrintf(ctx, 7, 464156952Sume " func %p, uap %p, due %ld.%09ld, inter %ld.%09ld\n", 465156952Sume cur->func, cur->uap, 466156952Sume (long)cur->due.tv_sec, cur->due.tv_nsec, 467156952Sume (long)cur->inter.tv_sec, cur->inter.tv_nsec); 468156952Sume} 469156952Sume 470156952Sumestatic void 471156952Sumeidle_timeout(evContext opaqueCtx, 472156952Sume void *uap, 473156952Sume struct timespec due, 474156952Sume struct timespec inter 475156952Sume) { 476156952Sume evContext_p *ctx = opaqueCtx.opaque; 477156952Sume idle_timer *this = uap; 478156952Sume struct timespec idle; 479156952Sume 480156952Sume UNUSED(due); 481156952Sume UNUSED(inter); 482156952Sume 483156952Sume idle = evSubTime(ctx->lastEventTime, this->lastTouched); 484156952Sume if (evCmpTime(idle, this->max_idle) >= 0) { 485156952Sume (this->func)(opaqueCtx, this->uap, this->timer->due, 486156952Sume this->max_idle); 487156952Sume /* 488156952Sume * Setting the interval to zero will cause the timer to 489156952Sume * be cleaned up in evDrop(). 490156952Sume */ 491156952Sume this->timer->inter = evConsTime(0, 0); 492156952Sume FREE(this); 493156952Sume } else { 494156952Sume /* evDrop() will reschedule the timer. */ 495156952Sume this->timer->inter = evSubTime(this->max_idle, idle); 496156952Sume } 497156952Sume} 498