1 /* 2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /* $Id: timer.c,v 1.1 2020/02/07 09:58:54 florian Exp $ */ 18 19 /*! \file */ 20 21 22 #include <stdlib.h> 23 #include <isc/app.h> 24 #include <isc/heap.h> 25 #include <isc/log.h> 26 #include <isc/magic.h> 27 #include <isc/msgs.h> 28 #include <isc/task.h> 29 #include <isc/time.h> 30 #include <isc/timer.h> 31 #include <isc/util.h> 32 33 #include "timer_p.h" 34 35 #ifdef ISC_TIMER_TRACE 36 #define XTRACE(s) fprintf(stderr, "%s\n", (s)) 37 #define XTRACEID(s, t) fprintf(stderr, "%s %p\n", (s), (t)) 38 #define XTRACETIME(s, d) fprintf(stderr, "%s %u.%09u\n", (s), \ 39 (d).seconds, (d).nanoseconds) 40 #define XTRACETIME2(s, d, n) fprintf(stderr, "%s %u.%09u %u.%09u\n", (s), \ 41 (d).seconds, (d).nanoseconds, (n).seconds, (n).nanoseconds) 42 #define XTRACETIMER(s, t, d) fprintf(stderr, "%s %p %u.%09u\n", (s), (t), \ 43 (d).seconds, (d).nanoseconds) 44 #else 45 #define XTRACE(s) 46 #define XTRACEID(s, t) 47 #define XTRACETIME(s, d) 48 #define XTRACETIME2(s, d, n) 49 #define XTRACETIMER(s, t, d) 50 #endif /* ISC_TIMER_TRACE */ 51 52 #define TIMER_MAGIC ISC_MAGIC('T', 'I', 'M', 'R') 53 #define VALID_TIMER(t) ISC_MAGIC_VALID(t, TIMER_MAGIC) 54 55 typedef struct isc__timer isc__timer_t; 56 typedef struct isc__timermgr isc__timermgr_t; 57 58 struct isc__timer { 59 /*! Not locked. */ 60 isc_timer_t common; 61 isc__timermgr_t * manager; 62 /*! Locked by timer lock. */ 63 unsigned int references; 64 isc_time_t idle; 65 /*! Locked by manager lock. */ 66 isc_timertype_t type; 67 isc_time_t expires; 68 interval_t interval; 69 isc_task_t * task; 70 isc_taskaction_t action; 71 void * arg; 72 unsigned int index; 73 isc_time_t due; 74 LINK(isc__timer_t) link; 75 }; 76 77 #define TIMER_MANAGER_MAGIC ISC_MAGIC('T', 'I', 'M', 'M') 78 #define VALID_MANAGER(m) ISC_MAGIC_VALID(m, TIMER_MANAGER_MAGIC) 79 80 struct isc__timermgr { 81 /* Not locked. */ 82 isc_timermgr_t common; 83 /* Locked by manager lock. */ 84 isc_boolean_t done; 85 LIST(isc__timer_t) timers; 86 unsigned int nscheduled; 87 isc_time_t due; 88 unsigned int refs; 89 isc_heap_t * heap; 90 }; 91 92 /*% 93 * The following are intended for internal use (indicated by "isc__" 94 * prefix) but are not declared as static, allowing direct access from 95 * unit tests etc. 96 */ 97 98 isc_result_t 99 isc__timer_create(isc_timermgr_t *manager, isc_timertype_t type, 100 const isc_time_t *expires, const interval_t *interval, 101 isc_task_t *task, isc_taskaction_t action, void *arg, 102 isc_timer_t **timerp); 103 isc_result_t 104 isc__timer_reset(isc_timer_t *timer, isc_timertype_t type, 105 const isc_time_t *expires, const interval_t *interval, 106 isc_boolean_t purge); 107 isc_timertype_t 108 isc_timer_gettype(isc_timer_t *timer); 109 isc_result_t 110 isc__timer_touch(isc_timer_t *timer); 111 void 112 isc__timer_attach(isc_timer_t *timer0, isc_timer_t **timerp); 113 void 114 isc__timer_detach(isc_timer_t **timerp); 115 isc_result_t 116 isc__timermgr_create(isc_timermgr_t **managerp); 117 void 118 isc_timermgr_poke(isc_timermgr_t *manager0); 119 void 120 isc__timermgr_destroy(isc_timermgr_t **managerp); 121 122 static struct isc__timermethods { 123 isc_timermethods_t methods; 124 125 /*% 126 * The following are defined just for avoiding unused static functions. 127 */ 128 void *gettype; 129 } timermethods = { 130 { 131 isc__timer_attach, 132 isc__timer_detach, 133 isc__timer_reset, 134 isc__timer_touch 135 }, 136 (void *)isc_timer_gettype 137 }; 138 139 static struct isc__timermgrmethods { 140 isc_timermgrmethods_t methods; 141 void *poke; /* see above */ 142 } timermgrmethods = { 143 { 144 isc__timermgr_destroy, 145 isc__timer_create 146 }, 147 (void *)isc_timermgr_poke 148 }; 149 150 /*! 151 * If the manager is supposed to be shared, there can be only one. 152 */ 153 static isc__timermgr_t *timermgr = NULL; 154 155 static inline isc_result_t 156 schedule(isc__timer_t *timer, isc_time_t *now, isc_boolean_t signal_ok) { 157 isc_result_t result; 158 isc__timermgr_t *manager; 159 isc_time_t due; 160 int cmp; 161 162 /*! 163 * Note: the caller must ensure locking. 164 */ 165 166 REQUIRE(timer->type != isc_timertype_inactive); 167 168 UNUSED(signal_ok); 169 170 manager = timer->manager; 171 172 /* 173 * Compute the new due time. 174 */ 175 if (timer->type != isc_timertype_once) { 176 result = isc_time_add(now, &timer->interval, &due); 177 if (result != ISC_R_SUCCESS) 178 return (result); 179 if (timer->type == isc_timertype_limited && 180 isc_time_compare(&timer->expires, &due) < 0) 181 due = timer->expires; 182 } else { 183 if (isc_time_isepoch(&timer->idle)) 184 due = timer->expires; 185 else if (isc_time_isepoch(&timer->expires)) 186 due = timer->idle; 187 else if (isc_time_compare(&timer->idle, &timer->expires) < 0) 188 due = timer->idle; 189 else 190 due = timer->expires; 191 } 192 193 /* 194 * Schedule the timer. 195 */ 196 197 if (timer->index > 0) { 198 /* 199 * Already scheduled. 200 */ 201 cmp = isc_time_compare(&due, &timer->due); 202 timer->due = due; 203 switch (cmp) { 204 case -1: 205 isc_heap_increased(manager->heap, timer->index); 206 break; 207 case 1: 208 isc_heap_decreased(manager->heap, timer->index); 209 break; 210 case 0: 211 /* Nothing to do. */ 212 break; 213 } 214 } else { 215 timer->due = due; 216 result = isc_heap_insert(manager->heap, timer); 217 if (result != ISC_R_SUCCESS) { 218 INSIST(result == ISC_R_NOMEMORY); 219 return (ISC_R_NOMEMORY); 220 } 221 manager->nscheduled++; 222 } 223 224 XTRACETIMER("schedule", timer, due); 225 226 /* 227 * If this timer is at the head of the queue, we need to ensure 228 * that we won't miss it if it has a more recent due time than 229 * the current "next" timer. We do this either by waking up the 230 * run thread, or explicitly setting the value in the manager. 231 */ 232 if (timer->index == 1 && 233 isc_time_compare(&timer->due, &manager->due) < 0) 234 manager->due = timer->due; 235 236 return (ISC_R_SUCCESS); 237 } 238 239 static inline void 240 deschedule(isc__timer_t *timer) { 241 isc__timermgr_t *manager; 242 243 /* 244 * The caller must ensure locking. 245 */ 246 247 manager = timer->manager; 248 if (timer->index > 0) { 249 isc_heap_delete(manager->heap, timer->index); 250 timer->index = 0; 251 INSIST(manager->nscheduled > 0); 252 manager->nscheduled--; 253 } 254 } 255 256 static void 257 destroy(isc__timer_t *timer) { 258 isc__timermgr_t *manager = timer->manager; 259 260 /* 261 * The caller must ensure it is safe to destroy the timer. 262 */ 263 264 (void)isc_task_purgerange(timer->task, 265 timer, 266 ISC_TIMEREVENT_FIRSTEVENT, 267 ISC_TIMEREVENT_LASTEVENT, 268 NULL); 269 deschedule(timer); 270 UNLINK(manager->timers, timer, link); 271 272 isc_task_detach(&timer->task); 273 timer->common.impmagic = 0; 274 timer->common.magic = 0; 275 free(timer); 276 } 277 278 isc_result_t 279 isc__timer_create(isc_timermgr_t *manager0, isc_timertype_t type, 280 const isc_time_t *expires, const interval_t *interval, 281 isc_task_t *task, isc_taskaction_t action, void *arg, 282 isc_timer_t **timerp) 283 { 284 isc__timermgr_t *manager = (isc__timermgr_t *)manager0; 285 isc__timer_t *timer; 286 isc_result_t result; 287 isc_time_t now; 288 289 /* 290 * Create a new 'type' timer managed by 'manager'. The timers 291 * parameters are specified by 'expires' and 'interval'. Events 292 * will be posted to 'task' and when dispatched 'action' will be 293 * called with 'arg' as the arg value. The new timer is returned 294 * in 'timerp'. 295 */ 296 297 REQUIRE(VALID_MANAGER(manager)); 298 REQUIRE(task != NULL); 299 REQUIRE(action != NULL); 300 if (expires == NULL) 301 expires = isc_time_epoch; 302 if (interval == NULL) 303 interval = interval_zero; 304 REQUIRE(type == isc_timertype_inactive || 305 !(isc_time_isepoch(expires) && interval_iszero(interval))); 306 REQUIRE(timerp != NULL && *timerp == NULL); 307 REQUIRE(type != isc_timertype_limited || 308 !(isc_time_isepoch(expires) || interval_iszero(interval))); 309 310 /* 311 * Get current time. 312 */ 313 if (type != isc_timertype_inactive) { 314 TIME_NOW(&now); 315 } else { 316 /* 317 * We don't have to do this, but it keeps the compiler from 318 * complaining about "now" possibly being used without being 319 * set, even though it will never actually happen. 320 */ 321 isc_time_settoepoch(&now); 322 } 323 324 325 timer = malloc(sizeof(*timer)); 326 if (timer == NULL) 327 return (ISC_R_NOMEMORY); 328 329 timer->manager = manager; 330 timer->references = 1; 331 332 if (type == isc_timertype_once && !interval_iszero(interval)) { 333 result = isc_time_add(&now, interval, &timer->idle); 334 if (result != ISC_R_SUCCESS) { 335 free(timer); 336 return (result); 337 } 338 } else 339 isc_time_settoepoch(&timer->idle); 340 341 timer->type = type; 342 timer->expires = *expires; 343 timer->interval = *interval; 344 timer->task = NULL; 345 isc_task_attach(task, &timer->task); 346 timer->action = action; 347 /* 348 * Removing the const attribute from "arg" is the best of two 349 * evils here. If the timer->arg member is made const, then 350 * it affects a great many recipients of the timer event 351 * which did not pass in an "arg" that was truly const. 352 * Changing isc_timer_create() to not have "arg" prototyped as const, 353 * though, can cause compilers warnings for calls that *do* 354 * have a truly const arg. The caller will have to carefully 355 * keep track of whether arg started as a true const. 356 */ 357 DE_CONST(arg, timer->arg); 358 timer->index = 0; 359 ISC_LINK_INIT(timer, link); 360 timer->common.impmagic = TIMER_MAGIC; 361 timer->common.magic = ISCAPI_TIMER_MAGIC; 362 timer->common.methods = (isc_timermethods_t *)&timermethods; 363 364 if (type != isc_timertype_inactive) 365 result = schedule(timer, &now, ISC_TRUE); 366 else 367 result = ISC_R_SUCCESS; 368 if (result == ISC_R_SUCCESS) 369 APPEND(manager->timers, timer, link); 370 371 if (result != ISC_R_SUCCESS) { 372 timer->common.impmagic = 0; 373 timer->common.magic = 0; 374 isc_task_detach(&timer->task); 375 free(timer); 376 return (result); 377 } 378 379 *timerp = (isc_timer_t *)timer; 380 381 return (ISC_R_SUCCESS); 382 } 383 384 isc_result_t 385 isc__timer_reset(isc_timer_t *timer0, isc_timertype_t type, 386 const isc_time_t *expires, const interval_t *interval, 387 isc_boolean_t purge) 388 { 389 isc__timer_t *timer = (isc__timer_t *)timer0; 390 isc_time_t now; 391 isc__timermgr_t *manager; 392 isc_result_t result; 393 394 /* 395 * Change the timer's type, expires, and interval values to the given 396 * values. If 'purge' is ISC_TRUE, any pending events from this timer 397 * are purged from its task's event queue. 398 */ 399 400 REQUIRE(VALID_TIMER(timer)); 401 manager = timer->manager; 402 REQUIRE(VALID_MANAGER(manager)); 403 404 if (expires == NULL) 405 expires = isc_time_epoch; 406 if (interval == NULL) 407 interval = interval_zero; 408 REQUIRE(type == isc_timertype_inactive || 409 !(isc_time_isepoch(expires) && interval_iszero(interval))); 410 REQUIRE(type != isc_timertype_limited || 411 !(isc_time_isepoch(expires) || interval_iszero(interval))); 412 413 /* 414 * Get current time. 415 */ 416 if (type != isc_timertype_inactive) { 417 TIME_NOW(&now); 418 } else { 419 /* 420 * We don't have to do this, but it keeps the compiler from 421 * complaining about "now" possibly being used without being 422 * set, even though it will never actually happen. 423 */ 424 isc_time_settoepoch(&now); 425 } 426 427 if (purge) 428 (void)isc_task_purgerange(timer->task, 429 timer, 430 ISC_TIMEREVENT_FIRSTEVENT, 431 ISC_TIMEREVENT_LASTEVENT, 432 NULL); 433 timer->type = type; 434 timer->expires = *expires; 435 timer->interval = *interval; 436 if (type == isc_timertype_once && !interval_iszero(interval)) { 437 result = isc_time_add(&now, interval, &timer->idle); 438 } else { 439 isc_time_settoepoch(&timer->idle); 440 result = ISC_R_SUCCESS; 441 } 442 443 if (result == ISC_R_SUCCESS) { 444 if (type == isc_timertype_inactive) { 445 deschedule(timer); 446 result = ISC_R_SUCCESS; 447 } else 448 result = schedule(timer, &now, ISC_TRUE); 449 } 450 451 return (result); 452 } 453 454 isc_timertype_t 455 isc_timer_gettype(isc_timer_t *timer0) { 456 isc__timer_t *timer = (isc__timer_t *)timer0; 457 isc_timertype_t t; 458 459 REQUIRE(VALID_TIMER(timer)); 460 461 t = timer->type; 462 463 return (t); 464 } 465 466 isc_result_t 467 isc__timer_touch(isc_timer_t *timer0) { 468 isc__timer_t *timer = (isc__timer_t *)timer0; 469 isc_result_t result; 470 isc_time_t now; 471 472 /* 473 * Set the last-touched time of 'timer' to the current time. 474 */ 475 476 REQUIRE(VALID_TIMER(timer)); 477 478 TIME_NOW(&now); 479 result = isc_time_add(&now, &timer->interval, &timer->idle); 480 481 return (result); 482 } 483 484 void 485 isc__timer_attach(isc_timer_t *timer0, isc_timer_t **timerp) { 486 isc__timer_t *timer = (isc__timer_t *)timer0; 487 488 /* 489 * Attach *timerp to timer. 490 */ 491 492 REQUIRE(VALID_TIMER(timer)); 493 REQUIRE(timerp != NULL && *timerp == NULL); 494 495 timer->references++; 496 497 *timerp = (isc_timer_t *)timer; 498 } 499 500 void 501 isc__timer_detach(isc_timer_t **timerp) { 502 isc__timer_t *timer; 503 isc_boolean_t free_timer = ISC_FALSE; 504 505 /* 506 * Detach *timerp from its timer. 507 */ 508 509 REQUIRE(timerp != NULL); 510 timer = (isc__timer_t *)*timerp; 511 REQUIRE(VALID_TIMER(timer)); 512 513 REQUIRE(timer->references > 0); 514 timer->references--; 515 if (timer->references == 0) 516 free_timer = ISC_TRUE; 517 518 if (free_timer) 519 destroy(timer); 520 521 *timerp = NULL; 522 } 523 524 static void 525 dispatch(isc__timermgr_t *manager, isc_time_t *now) { 526 isc_boolean_t done = ISC_FALSE, post_event, need_schedule; 527 isc_timerevent_t *event; 528 isc_eventtype_t type = 0; 529 isc__timer_t *timer; 530 isc_result_t result; 531 isc_boolean_t idle; 532 533 /*! 534 * The caller must be holding the manager lock. 535 */ 536 537 while (manager->nscheduled > 0 && !done) { 538 timer = isc_heap_element(manager->heap, 1); 539 INSIST(timer != NULL && timer->type != isc_timertype_inactive); 540 if (isc_time_compare(now, &timer->due) >= 0) { 541 if (timer->type == isc_timertype_ticker) { 542 type = ISC_TIMEREVENT_TICK; 543 post_event = ISC_TRUE; 544 need_schedule = ISC_TRUE; 545 } else if (timer->type == isc_timertype_limited) { 546 int cmp; 547 cmp = isc_time_compare(now, &timer->expires); 548 if (cmp >= 0) { 549 type = ISC_TIMEREVENT_LIFE; 550 post_event = ISC_TRUE; 551 need_schedule = ISC_FALSE; 552 } else { 553 type = ISC_TIMEREVENT_TICK; 554 post_event = ISC_TRUE; 555 need_schedule = ISC_TRUE; 556 } 557 } else if (!isc_time_isepoch(&timer->expires) && 558 isc_time_compare(now, 559 &timer->expires) >= 0) { 560 type = ISC_TIMEREVENT_LIFE; 561 post_event = ISC_TRUE; 562 need_schedule = ISC_FALSE; 563 } else { 564 idle = ISC_FALSE; 565 566 if (!isc_time_isepoch(&timer->idle) && 567 isc_time_compare(now, 568 &timer->idle) >= 0) { 569 idle = ISC_TRUE; 570 } 571 if (idle) { 572 type = ISC_TIMEREVENT_IDLE; 573 post_event = ISC_TRUE; 574 need_schedule = ISC_FALSE; 575 } else { 576 /* 577 * Idle timer has been touched; 578 * reschedule. 579 */ 580 XTRACEID("idle reschedule", timer); 581 post_event = ISC_FALSE; 582 need_schedule = ISC_TRUE; 583 } 584 } 585 586 if (post_event) { 587 XTRACEID("posting", timer); 588 /* 589 * XXX We could preallocate this event. 590 */ 591 event = (isc_timerevent_t *)isc_event_allocate( 592 timer, 593 type, 594 timer->action, 595 timer->arg, 596 sizeof(*event)); 597 598 if (event != NULL) { 599 event->due = timer->due; 600 isc_task_send(timer->task, 601 ISC_EVENT_PTR(&event)); 602 } else 603 UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", 604 "couldn't allocate event"); 605 } 606 607 timer->index = 0; 608 isc_heap_delete(manager->heap, 1); 609 manager->nscheduled--; 610 611 if (need_schedule) { 612 result = schedule(timer, now, ISC_FALSE); 613 if (result != ISC_R_SUCCESS) 614 UNEXPECTED_ERROR(__FILE__, __LINE__, 615 "%s: %u", 616 "couldn't schedule timer", 617 result); 618 } 619 } else { 620 manager->due = timer->due; 621 done = ISC_TRUE; 622 } 623 } 624 } 625 626 static isc_boolean_t 627 sooner(void *v1, void *v2) { 628 isc__timer_t *t1, *t2; 629 630 t1 = v1; 631 t2 = v2; 632 REQUIRE(VALID_TIMER(t1)); 633 REQUIRE(VALID_TIMER(t2)); 634 635 if (isc_time_compare(&t1->due, &t2->due) < 0) 636 return (ISC_TRUE); 637 return (ISC_FALSE); 638 } 639 640 static void 641 set_index(void *what, unsigned int index) { 642 isc__timer_t *timer; 643 644 timer = what; 645 REQUIRE(VALID_TIMER(timer)); 646 647 timer->index = index; 648 } 649 650 isc_result_t 651 isc__timermgr_create(isc_timermgr_t **managerp) { 652 isc__timermgr_t *manager; 653 isc_result_t result; 654 655 /* 656 * Create a timer manager. 657 */ 658 659 REQUIRE(managerp != NULL && *managerp == NULL); 660 661 if (timermgr != NULL) { 662 timermgr->refs++; 663 *managerp = (isc_timermgr_t *)timermgr; 664 return (ISC_R_SUCCESS); 665 } 666 667 manager = malloc(sizeof(*manager)); 668 if (manager == NULL) 669 return (ISC_R_NOMEMORY); 670 671 manager->common.impmagic = TIMER_MANAGER_MAGIC; 672 manager->common.magic = ISCAPI_TIMERMGR_MAGIC; 673 manager->common.methods = (isc_timermgrmethods_t *)&timermgrmethods; 674 manager->done = ISC_FALSE; 675 INIT_LIST(manager->timers); 676 manager->nscheduled = 0; 677 isc_time_settoepoch(&manager->due); 678 manager->heap = NULL; 679 result = isc_heap_create(sooner, set_index, 0, &manager->heap); 680 if (result != ISC_R_SUCCESS) { 681 INSIST(result == ISC_R_NOMEMORY); 682 free(manager); 683 return (ISC_R_NOMEMORY); 684 } 685 manager->refs = 1; 686 timermgr = manager; 687 688 *managerp = (isc_timermgr_t *)manager; 689 690 return (ISC_R_SUCCESS); 691 } 692 693 void 694 isc_timermgr_poke(isc_timermgr_t *manager0) { 695 UNUSED(manager0); 696 } 697 698 void 699 isc__timermgr_destroy(isc_timermgr_t **managerp) { 700 isc__timermgr_t *manager; 701 702 /* 703 * Destroy a timer manager. 704 */ 705 706 REQUIRE(managerp != NULL); 707 manager = (isc__timermgr_t *)*managerp; 708 REQUIRE(VALID_MANAGER(manager)); 709 710 manager->refs--; 711 if (manager->refs > 0) { 712 *managerp = NULL; 713 return; 714 } 715 timermgr = NULL; 716 717 isc__timermgr_dispatch((isc_timermgr_t *)manager); 718 719 REQUIRE(EMPTY(manager->timers)); 720 manager->done = ISC_TRUE; 721 722 /* 723 * Clean up. 724 */ 725 isc_heap_destroy(&manager->heap); 726 manager->common.impmagic = 0; 727 manager->common.magic = 0; 728 free(manager); 729 730 *managerp = NULL; 731 732 timermgr = NULL; 733 } 734 735 isc_result_t 736 isc__timermgr_nextevent(isc_timermgr_t *manager0, isc_time_t *when) { 737 isc__timermgr_t *manager = (isc__timermgr_t *)manager0; 738 739 if (manager == NULL) 740 manager = timermgr; 741 if (manager == NULL || manager->nscheduled == 0) 742 return (ISC_R_NOTFOUND); 743 *when = manager->due; 744 return (ISC_R_SUCCESS); 745 } 746 747 void 748 isc__timermgr_dispatch(isc_timermgr_t *manager0) { 749 isc__timermgr_t *manager = (isc__timermgr_t *)manager0; 750 isc_time_t now; 751 752 if (manager == NULL) 753 manager = timermgr; 754 if (manager == NULL) 755 return; 756 TIME_NOW(&now); 757 dispatch(manager, &now); 758 } 759 760 isc_result_t 761 isc__timer_register(void) { 762 return (isc_timer_register(isc__timermgr_create)); 763 } 764 765 static isc_timermgrcreatefunc_t timermgr_createfunc = NULL; 766 767 isc_result_t 768 isc_timer_register(isc_timermgrcreatefunc_t createfunc) { 769 isc_result_t result = ISC_R_SUCCESS; 770 771 if (timermgr_createfunc == NULL) 772 timermgr_createfunc = createfunc; 773 else 774 result = ISC_R_EXISTS; 775 776 return (result); 777 } 778 779 isc_result_t 780 isc_timermgr_createinctx(isc_appctx_t *actx, 781 isc_timermgr_t **managerp) 782 { 783 isc_result_t result; 784 785 REQUIRE(timermgr_createfunc != NULL); 786 result = (*timermgr_createfunc)(managerp); 787 788 if (result == ISC_R_SUCCESS) 789 isc_appctx_settimermgr(actx, *managerp); 790 791 return (result); 792 } 793 794 isc_result_t 795 isc_timermgr_create(isc_timermgr_t **managerp) { 796 return (isc__timermgr_create(managerp)); 797 } 798 799 void 800 isc_timermgr_destroy(isc_timermgr_t **managerp) { 801 REQUIRE(*managerp != NULL && ISCAPI_TIMERMGR_VALID(*managerp)); 802 803 isc__timermgr_destroy(managerp); 804 805 ENSURE(*managerp == NULL); 806 } 807 808 isc_result_t 809 isc_timer_create(isc_timermgr_t *manager, isc_timertype_t type, 810 const isc_time_t *expires, const interval_t *interval, 811 isc_task_t *task, isc_taskaction_t action, void *arg, 812 isc_timer_t **timerp) 813 { 814 REQUIRE(ISCAPI_TIMERMGR_VALID(manager)); 815 816 return (isc__timer_create(manager, type, expires, interval, 817 task, action, arg, timerp)); 818 } 819 820 void 821 isc_timer_attach(isc_timer_t *timer, isc_timer_t **timerp) { 822 REQUIRE(ISCAPI_TIMER_VALID(timer)); 823 REQUIRE(timerp != NULL && *timerp == NULL); 824 825 isc__timer_attach(timer, timerp); 826 827 ENSURE(*timerp == timer); 828 } 829 830 void 831 isc_timer_detach(isc_timer_t **timerp) { 832 REQUIRE(timerp != NULL && ISCAPI_TIMER_VALID(*timerp)); 833 834 isc__timer_detach(timerp); 835 836 ENSURE(*timerp == NULL); 837 } 838 839 isc_result_t 840 isc_timer_reset(isc_timer_t *timer, isc_timertype_t type, 841 const isc_time_t *expires, const interval_t *interval, 842 isc_boolean_t purge) 843 { 844 REQUIRE(ISCAPI_TIMER_VALID(timer)); 845 846 return (isc__timer_reset(timer, type, expires, 847 interval, purge)); 848 } 849 850 isc_result_t 851 isc_timer_touch(isc_timer_t *timer) { 852 REQUIRE(ISCAPI_TIMER_VALID(timer)); 853 854 return (isc__timer_touch(timer)); 855 } 856