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