2 * Copyright (C) 2004, 2005, 2007-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1998-2002 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
24 #include <isc/condition.h>
27 #include <isc/magic.h>
30 #include <isc/platform.h>
32 #include <isc/thread.h>
34 #include <isc/timer.h>
38 #include <openssl/err.h>
41 /* See task.c about the following definition: */
43 #ifdef ISC_PLATFORM_USETHREADS
44 #define USE_TIMER_THREAD
46 #define USE_SHARED_MANAGER
47 #endif /* ISC_PLATFORM_USETHREADS */
50 #ifndef USE_TIMER_THREAD
52 #endif /* USE_TIMER_THREAD */
54 #ifdef ISC_TIMER_TRACE
55 #define XTRACE(s) fprintf(stderr, "%s\n", (s))
56 #define XTRACEID(s, t) fprintf(stderr, "%s %p\n", (s), (t))
57 #define XTRACETIME(s, d) fprintf(stderr, "%s %u.%09u\n", (s), \
58 (d).seconds, (d).nanoseconds)
59 #define XTRACETIME2(s, d, n) fprintf(stderr, "%s %u.%09u %u.%09u\n", (s), \
60 (d).seconds, (d).nanoseconds, (n).seconds, (n).nanoseconds)
61 #define XTRACETIMER(s, t, d) fprintf(stderr, "%s %p %u.%09u\n", (s), (t), \
62 (d).seconds, (d).nanoseconds)
65 #define XTRACEID(s, t)
66 #define XTRACETIME(s, d)
67 #define XTRACETIME2(s, d, n)
68 #define XTRACETIMER(s, t, d)
69 #endif /* ISC_TIMER_TRACE */
71 #define TIMER_MAGIC ISC_MAGIC('T', 'I', 'M', 'R')
72 #define VALID_TIMER(t) ISC_MAGIC_VALID(t, TIMER_MAGIC)
74 typedef struct isc__timer isc__timer_t;
75 typedef struct isc__timermgr isc__timermgr_t;
80 isc__timermgr_t * manager;
82 /*! Locked by timer lock. */
83 unsigned int references;
85 /*! Locked by manager lock. */
88 isc_interval_t interval;
90 isc_taskaction_t action;
94 LINK(isc__timer_t) link;
97 #define TIMER_MANAGER_MAGIC ISC_MAGIC('T', 'I', 'M', 'M')
98 #define VALID_MANAGER(m) ISC_MAGIC_VALID(m, TIMER_MANAGER_MAGIC)
100 struct isc__timermgr {
102 isc_timermgr_t common;
105 /* Locked by manager lock. */
107 LIST(isc__timer_t) timers;
108 unsigned int nscheduled;
110 #ifdef USE_TIMER_THREAD
111 isc_condition_t wakeup;
113 #endif /* USE_TIMER_THREAD */
114 #ifdef USE_SHARED_MANAGER
116 #endif /* USE_SHARED_MANAGER */
121 * The followings can be either static or public, depending on build
126 #define ISC_TIMERFUNC_SCOPE
128 #define ISC_TIMERFUNC_SCOPE static
131 ISC_TIMERFUNC_SCOPE isc_result_t
132 isc__timer_create(isc_timermgr_t *manager, isc_timertype_t type,
133 isc_time_t *expires, isc_interval_t *interval,
134 isc_task_t *task, isc_taskaction_t action, const void *arg,
135 isc_timer_t **timerp);
136 ISC_TIMERFUNC_SCOPE isc_result_t
137 isc__timer_reset(isc_timer_t *timer, isc_timertype_t type,
138 isc_time_t *expires, isc_interval_t *interval,
139 isc_boolean_t purge);
140 ISC_TIMERFUNC_SCOPE isc_timertype_t
141 isc__timer_gettype(isc_timer_t *timer);
142 ISC_TIMERFUNC_SCOPE isc_result_t
143 isc__timer_touch(isc_timer_t *timer);
144 ISC_TIMERFUNC_SCOPE void
145 isc__timer_attach(isc_timer_t *timer0, isc_timer_t **timerp);
146 ISC_TIMERFUNC_SCOPE void
147 isc__timer_detach(isc_timer_t **timerp);
148 ISC_TIMERFUNC_SCOPE isc_result_t
149 isc__timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp);
150 ISC_TIMERFUNC_SCOPE void
151 isc__timermgr_poke(isc_timermgr_t *manager0);
152 ISC_TIMERFUNC_SCOPE void
153 isc__timermgr_destroy(isc_timermgr_t **managerp);
155 static struct isc__timermethods {
156 isc_timermethods_t methods;
159 * The following are defined just for avoiding unused static functions.
173 (void *)isc__timer_gettype
177 static struct isc__timermgrmethods {
178 isc_timermgrmethods_t methods;
180 void *poke; /* see above */
182 } timermgrmethods = {
184 isc__timermgr_destroy,
189 (void *)isc__timermgr_poke
193 #ifdef USE_SHARED_MANAGER
195 * If the manager is supposed to be shared, there can be only one.
197 static isc__timermgr_t *timermgr = NULL;
198 #endif /* USE_SHARED_MANAGER */
200 static inline isc_result_t
201 schedule(isc__timer_t *timer, isc_time_t *now, isc_boolean_t signal_ok) {
203 isc__timermgr_t *manager;
206 #ifdef USE_TIMER_THREAD
207 isc_boolean_t timedwait;
211 * Note: the caller must ensure locking.
214 REQUIRE(timer->type != isc_timertype_inactive);
216 #ifndef USE_TIMER_THREAD
218 #endif /* USE_TIMER_THREAD */
220 manager = timer->manager;
222 #ifdef USE_TIMER_THREAD
224 * If the manager was timed wait, we may need to signal the
225 * manager to force a wakeup.
227 timedwait = ISC_TF(manager->nscheduled > 0 &&
228 isc_time_seconds(&manager->due) != 0);
232 * Compute the new due time.
234 if (timer->type != isc_timertype_once) {
235 result = isc_time_add(now, &timer->interval, &due);
236 if (result != ISC_R_SUCCESS)
238 if (timer->type == isc_timertype_limited &&
239 isc_time_compare(&timer->expires, &due) < 0)
240 due = timer->expires;
242 if (isc_time_isepoch(&timer->idle))
243 due = timer->expires;
244 else if (isc_time_isepoch(&timer->expires))
246 else if (isc_time_compare(&timer->idle, &timer->expires) < 0)
249 due = timer->expires;
253 * Schedule the timer.
256 if (timer->index > 0) {
260 cmp = isc_time_compare(&due, &timer->due);
264 isc_heap_increased(manager->heap, timer->index);
267 isc_heap_decreased(manager->heap, timer->index);
275 result = isc_heap_insert(manager->heap, timer);
276 if (result != ISC_R_SUCCESS) {
277 INSIST(result == ISC_R_NOMEMORY);
278 return (ISC_R_NOMEMORY);
280 manager->nscheduled++;
283 XTRACETIMER(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
284 ISC_MSG_SCHEDULE, "schedule"), timer, due);
287 * If this timer is at the head of the queue, we need to ensure
288 * that we won't miss it if it has a more recent due time than
289 * the current "next" timer. We do this either by waking up the
290 * run thread, or explicitly setting the value in the manager.
292 #ifdef USE_TIMER_THREAD
295 * This is a temporary (probably) hack to fix a bug on tru64 5.1
296 * and 5.1a. Sometimes, pthread_cond_timedwait() doesn't actually
297 * return when the time expires, so here, we check to see if
298 * we're 15 seconds or more behind, and if we are, we signal
299 * the dispatcher. This isn't such a bad idea as a general purpose
300 * watchdog, so perhaps we should just leave it in here.
302 if (signal_ok && timedwait) {
303 isc_interval_t fifteen;
306 isc_interval_set(&fifteen, 15, 0);
307 result = isc_time_add(&manager->due, &fifteen, &then);
309 if (result == ISC_R_SUCCESS &&
310 isc_time_compare(&then, now) < 0) {
311 SIGNAL(&manager->wakeup);
312 signal_ok = ISC_FALSE;
313 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
314 ISC_LOGMODULE_TIMER, ISC_LOG_WARNING,
315 "*** POKED TIMER ***");
319 if (timer->index == 1 && signal_ok) {
320 XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
322 "signal (schedule)"));
323 SIGNAL(&manager->wakeup);
325 #else /* USE_TIMER_THREAD */
326 if (timer->index == 1 &&
327 isc_time_compare(&timer->due, &manager->due) < 0)
328 manager->due = timer->due;
329 #endif /* USE_TIMER_THREAD */
331 return (ISC_R_SUCCESS);
335 deschedule(isc__timer_t *timer) {
336 #ifdef USE_TIMER_THREAD
337 isc_boolean_t need_wakeup = ISC_FALSE;
339 isc__timermgr_t *manager;
342 * The caller must ensure locking.
345 manager = timer->manager;
346 if (timer->index > 0) {
347 #ifdef USE_TIMER_THREAD
348 if (timer->index == 1)
349 need_wakeup = ISC_TRUE;
351 isc_heap_delete(manager->heap, timer->index);
353 INSIST(manager->nscheduled > 0);
354 manager->nscheduled--;
355 #ifdef USE_TIMER_THREAD
357 XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
358 ISC_MSG_SIGNALDESCHED,
359 "signal (deschedule)"));
360 SIGNAL(&manager->wakeup);
362 #endif /* USE_TIMER_THREAD */
367 destroy(isc__timer_t *timer) {
368 isc__timermgr_t *manager = timer->manager;
371 * The caller must ensure it is safe to destroy the timer.
374 LOCK(&manager->lock);
376 (void)isc_task_purgerange(timer->task,
378 ISC_TIMEREVENT_FIRSTEVENT,
379 ISC_TIMEREVENT_LASTEVENT,
382 UNLINK(manager->timers, timer, link);
384 UNLOCK(&manager->lock);
386 isc_task_detach(&timer->task);
387 DESTROYLOCK(&timer->lock);
388 timer->common.impmagic = 0;
389 timer->common.magic = 0;
390 isc_mem_put(manager->mctx, timer, sizeof(*timer));
393 ISC_TIMERFUNC_SCOPE isc_result_t
394 isc__timer_create(isc_timermgr_t *manager0, isc_timertype_t type,
395 isc_time_t *expires, isc_interval_t *interval,
396 isc_task_t *task, isc_taskaction_t action, const void *arg,
397 isc_timer_t **timerp)
399 isc__timermgr_t *manager = (isc__timermgr_t *)manager0;
405 * Create a new 'type' timer managed by 'manager'. The timers
406 * parameters are specified by 'expires' and 'interval'. Events
407 * will be posted to 'task' and when dispatched 'action' will be
408 * called with 'arg' as the arg value. The new timer is returned
412 REQUIRE(VALID_MANAGER(manager));
413 REQUIRE(task != NULL);
414 REQUIRE(action != NULL);
416 expires = isc_time_epoch;
417 if (interval == NULL)
418 interval = isc_interval_zero;
419 REQUIRE(type == isc_timertype_inactive ||
420 !(isc_time_isepoch(expires) && isc_interval_iszero(interval)));
421 REQUIRE(timerp != NULL && *timerp == NULL);
422 REQUIRE(type != isc_timertype_limited ||
423 !(isc_time_isepoch(expires) || isc_interval_iszero(interval)));
428 if (type != isc_timertype_inactive) {
432 * We don't have to do this, but it keeps the compiler from
433 * complaining about "now" possibly being used without being
434 * set, even though it will never actually happen.
436 isc_time_settoepoch(&now);
440 timer = isc_mem_get(manager->mctx, sizeof(*timer));
442 return (ISC_R_NOMEMORY);
444 timer->manager = manager;
445 timer->references = 1;
447 if (type == isc_timertype_once && !isc_interval_iszero(interval)) {
448 result = isc_time_add(&now, interval, &timer->idle);
449 if (result != ISC_R_SUCCESS) {
450 isc_mem_put(manager->mctx, timer, sizeof(*timer));
454 isc_time_settoepoch(&timer->idle);
457 timer->expires = *expires;
458 timer->interval = *interval;
460 isc_task_attach(task, &timer->task);
461 timer->action = action;
463 * Removing the const attribute from "arg" is the best of two
464 * evils here. If the timer->arg member is made const, then
465 * it affects a great many recipients of the timer event
466 * which did not pass in an "arg" that was truly const.
467 * Changing isc_timer_create() to not have "arg" prototyped as const,
468 * though, can cause compilers warnings for calls that *do*
469 * have a truly const arg. The caller will have to carefully
470 * keep track of whether arg started as a true const.
472 DE_CONST(arg, timer->arg);
474 result = isc_mutex_init(&timer->lock);
475 if (result != ISC_R_SUCCESS) {
476 isc_task_detach(&timer->task);
477 isc_mem_put(manager->mctx, timer, sizeof(*timer));
480 ISC_LINK_INIT(timer, link);
481 timer->common.impmagic = TIMER_MAGIC;
482 timer->common.magic = ISCAPI_TIMER_MAGIC;
483 timer->common.methods = (isc_timermethods_t *)&timermethods;
485 LOCK(&manager->lock);
488 * Note we don't have to lock the timer like we normally would because
489 * there are no external references to it yet.
492 if (type != isc_timertype_inactive)
493 result = schedule(timer, &now, ISC_TRUE);
495 result = ISC_R_SUCCESS;
496 if (result == ISC_R_SUCCESS)
497 APPEND(manager->timers, timer, link);
499 UNLOCK(&manager->lock);
501 if (result != ISC_R_SUCCESS) {
502 timer->common.impmagic = 0;
503 timer->common.magic = 0;
504 DESTROYLOCK(&timer->lock);
505 isc_task_detach(&timer->task);
506 isc_mem_put(manager->mctx, timer, sizeof(*timer));
510 *timerp = (isc_timer_t *)timer;
512 return (ISC_R_SUCCESS);
515 ISC_TIMERFUNC_SCOPE isc_result_t
516 isc__timer_reset(isc_timer_t *timer0, isc_timertype_t type,
517 isc_time_t *expires, isc_interval_t *interval,
520 isc__timer_t *timer = (isc__timer_t *)timer0;
522 isc__timermgr_t *manager;
526 * Change the timer's type, expires, and interval values to the given
527 * values. If 'purge' is ISC_TRUE, any pending events from this timer
528 * are purged from its task's event queue.
531 REQUIRE(VALID_TIMER(timer));
532 manager = timer->manager;
533 REQUIRE(VALID_MANAGER(manager));
536 expires = isc_time_epoch;
537 if (interval == NULL)
538 interval = isc_interval_zero;
539 REQUIRE(type == isc_timertype_inactive ||
540 !(isc_time_isepoch(expires) && isc_interval_iszero(interval)));
541 REQUIRE(type != isc_timertype_limited ||
542 !(isc_time_isepoch(expires) || isc_interval_iszero(interval)));
547 if (type != isc_timertype_inactive) {
551 * We don't have to do this, but it keeps the compiler from
552 * complaining about "now" possibly being used without being
553 * set, even though it will never actually happen.
555 isc_time_settoepoch(&now);
558 LOCK(&manager->lock);
562 (void)isc_task_purgerange(timer->task,
564 ISC_TIMEREVENT_FIRSTEVENT,
565 ISC_TIMEREVENT_LASTEVENT,
568 timer->expires = *expires;
569 timer->interval = *interval;
570 if (type == isc_timertype_once && !isc_interval_iszero(interval)) {
571 result = isc_time_add(&now, interval, &timer->idle);
573 isc_time_settoepoch(&timer->idle);
574 result = ISC_R_SUCCESS;
577 if (result == ISC_R_SUCCESS) {
578 if (type == isc_timertype_inactive) {
580 result = ISC_R_SUCCESS;
582 result = schedule(timer, &now, ISC_TRUE);
585 UNLOCK(&timer->lock);
586 UNLOCK(&manager->lock);
591 ISC_TIMERFUNC_SCOPE isc_timertype_t
592 isc__timer_gettype(isc_timer_t *timer0) {
593 isc__timer_t *timer = (isc__timer_t *)timer0;
596 REQUIRE(VALID_TIMER(timer));
600 UNLOCK(&timer->lock);
605 ISC_TIMERFUNC_SCOPE isc_result_t
606 isc__timer_touch(isc_timer_t *timer0) {
607 isc__timer_t *timer = (isc__timer_t *)timer0;
612 * Set the last-touched time of 'timer' to the current time.
615 REQUIRE(VALID_TIMER(timer));
622 * REQUIRE(timer->type == isc_timertype_once);
624 * but we cannot without locking the manager lock too, which we
629 result = isc_time_add(&now, &timer->interval, &timer->idle);
631 UNLOCK(&timer->lock);
636 ISC_TIMERFUNC_SCOPE void
637 isc__timer_attach(isc_timer_t *timer0, isc_timer_t **timerp) {
638 isc__timer_t *timer = (isc__timer_t *)timer0;
641 * Attach *timerp to timer.
644 REQUIRE(VALID_TIMER(timer));
645 REQUIRE(timerp != NULL && *timerp == NULL);
649 UNLOCK(&timer->lock);
651 *timerp = (isc_timer_t *)timer;
654 ISC_TIMERFUNC_SCOPE void
655 isc__timer_detach(isc_timer_t **timerp) {
657 isc_boolean_t free_timer = ISC_FALSE;
660 * Detach *timerp from its timer.
663 REQUIRE(timerp != NULL);
664 timer = (isc__timer_t *)*timerp;
665 REQUIRE(VALID_TIMER(timer));
668 REQUIRE(timer->references > 0);
670 if (timer->references == 0)
671 free_timer = ISC_TRUE;
672 UNLOCK(&timer->lock);
681 dispatch(isc__timermgr_t *manager, isc_time_t *now) {
682 isc_boolean_t done = ISC_FALSE, post_event, need_schedule;
683 isc_timerevent_t *event;
684 isc_eventtype_t type = 0;
690 * The caller must be holding the manager lock.
693 while (manager->nscheduled > 0 && !done) {
694 timer = isc_heap_element(manager->heap, 1);
695 INSIST(timer->type != isc_timertype_inactive);
696 if (isc_time_compare(now, &timer->due) >= 0) {
697 if (timer->type == isc_timertype_ticker) {
698 type = ISC_TIMEREVENT_TICK;
699 post_event = ISC_TRUE;
700 need_schedule = ISC_TRUE;
701 } else if (timer->type == isc_timertype_limited) {
703 cmp = isc_time_compare(now, &timer->expires);
705 type = ISC_TIMEREVENT_LIFE;
706 post_event = ISC_TRUE;
707 need_schedule = ISC_FALSE;
709 type = ISC_TIMEREVENT_TICK;
710 post_event = ISC_TRUE;
711 need_schedule = ISC_TRUE;
713 } else if (!isc_time_isepoch(&timer->expires) &&
714 isc_time_compare(now,
715 &timer->expires) >= 0) {
716 type = ISC_TIMEREVENT_LIFE;
717 post_event = ISC_TRUE;
718 need_schedule = ISC_FALSE;
723 if (!isc_time_isepoch(&timer->idle) &&
724 isc_time_compare(now,
725 &timer->idle) >= 0) {
728 UNLOCK(&timer->lock);
730 type = ISC_TIMEREVENT_IDLE;
731 post_event = ISC_TRUE;
732 need_schedule = ISC_FALSE;
735 * Idle timer has been touched;
738 XTRACEID(isc_msgcat_get(isc_msgcat,
743 post_event = ISC_FALSE;
744 need_schedule = ISC_TRUE;
749 XTRACEID(isc_msgcat_get(isc_msgcat,
754 * XXX We could preallocate this event.
756 event = (isc_timerevent_t *)isc_event_allocate(manager->mctx,
764 event->due = timer->due;
765 isc_task_send(timer->task,
766 ISC_EVENT_PTR(&event));
768 UNEXPECTED_ERROR(__FILE__, __LINE__, "%s",
769 isc_msgcat_get(isc_msgcat,
771 ISC_MSG_EVENTNOTALLOC,
777 isc_heap_delete(manager->heap, 1);
778 manager->nscheduled--;
781 result = schedule(timer, now, ISC_FALSE);
782 if (result != ISC_R_SUCCESS)
783 UNEXPECTED_ERROR(__FILE__, __LINE__,
785 isc_msgcat_get(isc_msgcat,
793 manager->due = timer->due;
799 #ifdef USE_TIMER_THREAD
800 static isc_threadresult_t
801 #ifdef _WIN32 /* XXXDCL */
805 isc__timermgr_t *manager = uap;
809 LOCK(&manager->lock);
810 while (!manager->done) {
813 XTRACETIME(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
817 dispatch(manager, &now);
819 if (manager->nscheduled > 0) {
820 XTRACETIME2(isc_msgcat_get(isc_msgcat,
825 result = WAITUNTIL(&manager->wakeup, &manager->lock, &manager->due);
826 INSIST(result == ISC_R_SUCCESS ||
827 result == ISC_R_TIMEDOUT);
829 XTRACETIME(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
830 ISC_MSG_WAIT, "wait"), now);
831 WAIT(&manager->wakeup, &manager->lock);
833 XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
834 ISC_MSG_WAKEUP, "wakeup"));
836 UNLOCK(&manager->lock);
842 return ((isc_threadresult_t)0);
844 #endif /* USE_TIMER_THREAD */
847 sooner(void *v1, void *v2) {
848 isc__timer_t *t1, *t2;
852 REQUIRE(VALID_TIMER(t1));
853 REQUIRE(VALID_TIMER(t2));
855 if (isc_time_compare(&t1->due, &t2->due) < 0)
861 set_index(void *what, unsigned int index) {
865 REQUIRE(VALID_TIMER(timer));
867 timer->index = index;
870 ISC_TIMERFUNC_SCOPE isc_result_t
871 isc__timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) {
872 isc__timermgr_t *manager;
876 * Create a timer manager.
879 REQUIRE(managerp != NULL && *managerp == NULL);
881 #ifdef USE_SHARED_MANAGER
882 if (timermgr != NULL) {
884 *managerp = (isc_timermgr_t *)timermgr;
885 return (ISC_R_SUCCESS);
887 #endif /* USE_SHARED_MANAGER */
889 manager = isc_mem_get(mctx, sizeof(*manager));
891 return (ISC_R_NOMEMORY);
893 manager->common.impmagic = TIMER_MANAGER_MAGIC;
894 manager->common.magic = ISCAPI_TIMERMGR_MAGIC;
895 manager->common.methods = (isc_timermgrmethods_t *)&timermgrmethods;
896 manager->mctx = NULL;
897 manager->done = ISC_FALSE;
898 INIT_LIST(manager->timers);
899 manager->nscheduled = 0;
900 isc_time_settoepoch(&manager->due);
901 manager->heap = NULL;
902 result = isc_heap_create(mctx, sooner, set_index, 0, &manager->heap);
903 if (result != ISC_R_SUCCESS) {
904 INSIST(result == ISC_R_NOMEMORY);
905 isc_mem_put(mctx, manager, sizeof(*manager));
906 return (ISC_R_NOMEMORY);
908 result = isc_mutex_init(&manager->lock);
909 if (result != ISC_R_SUCCESS) {
910 isc_heap_destroy(&manager->heap);
911 isc_mem_put(mctx, manager, sizeof(*manager));
914 isc_mem_attach(mctx, &manager->mctx);
915 #ifdef USE_TIMER_THREAD
916 if (isc_condition_init(&manager->wakeup) != ISC_R_SUCCESS) {
917 isc_mem_detach(&manager->mctx);
918 DESTROYLOCK(&manager->lock);
919 isc_heap_destroy(&manager->heap);
920 isc_mem_put(mctx, manager, sizeof(*manager));
921 UNEXPECTED_ERROR(__FILE__, __LINE__,
922 "isc_condition_init() %s",
923 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
924 ISC_MSG_FAILED, "failed"));
925 return (ISC_R_UNEXPECTED);
927 if (isc_thread_create(run, manager, &manager->thread) !=
929 isc_mem_detach(&manager->mctx);
930 (void)isc_condition_destroy(&manager->wakeup);
931 DESTROYLOCK(&manager->lock);
932 isc_heap_destroy(&manager->heap);
933 isc_mem_put(mctx, manager, sizeof(*manager));
934 UNEXPECTED_ERROR(__FILE__, __LINE__,
935 "isc_thread_create() %s",
936 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
937 ISC_MSG_FAILED, "failed"));
938 return (ISC_R_UNEXPECTED);
941 #ifdef USE_SHARED_MANAGER
944 #endif /* USE_SHARED_MANAGER */
946 *managerp = (isc_timermgr_t *)manager;
948 return (ISC_R_SUCCESS);
951 ISC_TIMERFUNC_SCOPE void
952 isc__timermgr_poke(isc_timermgr_t *manager0) {
953 #ifdef USE_TIMER_THREAD
954 isc__timermgr_t *manager = (isc__timermgr_t *)manager0;
956 REQUIRE(VALID_MANAGER(manager));
958 SIGNAL(&manager->wakeup);
964 ISC_TIMERFUNC_SCOPE void
965 isc__timermgr_destroy(isc_timermgr_t **managerp) {
966 isc__timermgr_t *manager;
970 * Destroy a timer manager.
973 REQUIRE(managerp != NULL);
974 manager = (isc__timermgr_t *)*managerp;
975 REQUIRE(VALID_MANAGER(manager));
977 LOCK(&manager->lock);
979 #ifdef USE_SHARED_MANAGER
981 if (manager->refs > 0) {
982 UNLOCK(&manager->lock);
987 #endif /* USE_SHARED_MANAGER */
989 #ifndef USE_TIMER_THREAD
990 isc__timermgr_dispatch((isc_timermgr_t *)manager);
993 REQUIRE(EMPTY(manager->timers));
994 manager->done = ISC_TRUE;
996 #ifdef USE_TIMER_THREAD
997 XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
998 ISC_MSG_SIGNALDESTROY, "signal (destroy)"));
999 SIGNAL(&manager->wakeup);
1000 #endif /* USE_TIMER_THREAD */
1002 UNLOCK(&manager->lock);
1004 #ifdef USE_TIMER_THREAD
1006 * Wait for thread to exit.
1008 if (isc_thread_join(manager->thread, NULL) != ISC_R_SUCCESS)
1009 UNEXPECTED_ERROR(__FILE__, __LINE__,
1010 "isc_thread_join() %s",
1011 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
1012 ISC_MSG_FAILED, "failed"));
1013 #endif /* USE_TIMER_THREAD */
1018 #ifdef USE_TIMER_THREAD
1019 (void)isc_condition_destroy(&manager->wakeup);
1020 #endif /* USE_TIMER_THREAD */
1021 DESTROYLOCK(&manager->lock);
1022 isc_heap_destroy(&manager->heap);
1023 manager->common.impmagic = 0;
1024 manager->common.magic = 0;
1025 mctx = manager->mctx;
1026 isc_mem_put(mctx, manager, sizeof(*manager));
1027 isc_mem_detach(&mctx);
1031 #ifdef USE_SHARED_MANAGER
1036 #ifndef USE_TIMER_THREAD
1038 isc__timermgr_nextevent(isc_timermgr_t *manager0, isc_time_t *when) {
1039 isc__timermgr_t *manager = (isc__timermgr_t *)manager0;
1041 #ifdef USE_SHARED_MANAGER
1042 if (manager == NULL)
1045 if (manager == NULL || manager->nscheduled == 0)
1046 return (ISC_R_NOTFOUND);
1047 *when = manager->due;
1048 return (ISC_R_SUCCESS);
1052 isc__timermgr_dispatch(isc_timermgr_t *manager0) {
1053 isc__timermgr_t *manager = (isc__timermgr_t *)manager0;
1056 #ifdef USE_SHARED_MANAGER
1057 if (manager == NULL)
1060 if (manager == NULL)
1063 dispatch(manager, &now);
1065 #endif /* USE_TIMER_THREAD */
1067 #ifdef USE_TIMERIMPREGISTER
1069 isc__timer_register() {
1070 return (isc_timer_register(isc__timermgr_create));