4 * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1998-2002 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or 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.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: timer.c,v 1.84.58.4 2009/01/23 23:47:21 tbox Exp */
26 #include <isc/condition.h>
29 #include <isc/magic.h>
32 #include <isc/platform.h>
34 #include <isc/thread.h>
36 #include <isc/timer.h>
39 #ifndef ISC_PLATFORM_USETHREADS
41 #endif /* ISC_PLATFORM_USETHREADS */
43 #ifdef ISC_TIMER_TRACE
44 #define XTRACE(s) fprintf(stderr, "%s\n", (s))
45 #define XTRACEID(s, t) fprintf(stderr, "%s %p\n", (s), (t))
46 #define XTRACETIME(s, d) fprintf(stderr, "%s %u.%09u\n", (s), \
47 (d).seconds, (d).nanoseconds)
48 #define XTRACETIME2(s, d, n) fprintf(stderr, "%s %u.%09u %u.%09u\n", (s), \
49 (d).seconds, (d).nanoseconds, (n).seconds, (n).nanoseconds)
50 #define XTRACETIMER(s, t, d) fprintf(stderr, "%s %p %u.%09u\n", (s), (t), \
51 (d).seconds, (d).nanoseconds)
54 #define XTRACEID(s, t)
55 #define XTRACETIME(s, d)
56 #define XTRACETIME2(s, d, n)
57 #define XTRACETIMER(s, t, d)
58 #endif /* ISC_TIMER_TRACE */
60 #define TIMER_MAGIC ISC_MAGIC('T', 'I', 'M', 'R')
61 #define VALID_TIMER(t) ISC_MAGIC_VALID(t, TIMER_MAGIC)
66 isc_timermgr_t
* manager
;
68 /*! Locked by timer lock. */
69 unsigned int references
;
71 /*! Locked by manager lock. */
74 isc_interval_t interval
;
76 isc_taskaction_t action
;
80 LINK(isc_timer_t
) link
;
83 #define TIMER_MANAGER_MAGIC ISC_MAGIC('T', 'I', 'M', 'M')
84 #define VALID_MANAGER(m) ISC_MAGIC_VALID(m, TIMER_MANAGER_MAGIC)
91 /* Locked by manager lock. */
93 LIST(isc_timer_t
) timers
;
94 unsigned int nscheduled
;
96 #ifdef ISC_PLATFORM_USETHREADS
97 isc_condition_t wakeup
;
99 #else /* ISC_PLATFORM_USETHREADS */
101 #endif /* ISC_PLATFORM_USETHREADS */
105 #ifndef ISC_PLATFORM_USETHREADS
107 * If threads are not in use, there can be only one.
109 static isc_timermgr_t
*timermgr
= NULL
;
110 #endif /* ISC_PLATFORM_USETHREADS */
112 static inline isc_result_t
113 schedule(isc_timer_t
*timer
, isc_time_t
*now
, isc_boolean_t signal_ok
) {
115 isc_timermgr_t
*manager
;
118 #ifdef ISC_PLATFORM_USETHREADS
119 isc_boolean_t timedwait
;
123 * Note: the caller must ensure locking.
126 REQUIRE(timer
->type
!= isc_timertype_inactive
);
128 #ifndef ISC_PLATFORM_USETHREADS
130 #endif /* ISC_PLATFORM_USETHREADS */
132 manager
= timer
->manager
;
134 #ifdef ISC_PLATFORM_USETHREADS
136 * If the manager was timed wait, we may need to signal the
137 * manager to force a wakeup.
139 timedwait
= ISC_TF(manager
->nscheduled
> 0 &&
140 isc_time_seconds(&manager
->due
) != 0);
144 * Compute the new due time.
146 if (timer
->type
!= isc_timertype_once
) {
147 result
= isc_time_add(now
, &timer
->interval
, &due
);
148 if (result
!= ISC_R_SUCCESS
)
150 if (timer
->type
== isc_timertype_limited
&&
151 isc_time_compare(&timer
->expires
, &due
) < 0)
152 due
= timer
->expires
;
154 if (isc_time_isepoch(&timer
->idle
))
155 due
= timer
->expires
;
156 else if (isc_time_isepoch(&timer
->expires
))
158 else if (isc_time_compare(&timer
->idle
, &timer
->expires
) < 0)
161 due
= timer
->expires
;
165 * Schedule the timer.
168 if (timer
->index
> 0) {
172 cmp
= isc_time_compare(&due
, &timer
->due
);
176 isc_heap_increased(manager
->heap
, timer
->index
);
179 isc_heap_decreased(manager
->heap
, timer
->index
);
187 result
= isc_heap_insert(manager
->heap
, timer
);
188 if (result
!= ISC_R_SUCCESS
) {
189 INSIST(result
== ISC_R_NOMEMORY
);
190 return (ISC_R_NOMEMORY
);
192 manager
->nscheduled
++;
195 XTRACETIMER(isc_msgcat_get(isc_msgcat
, ISC_MSGSET_TIMER
,
196 ISC_MSG_SCHEDULE
, "schedule"), timer
, due
);
199 * If this timer is at the head of the queue, we need to ensure
200 * that we won't miss it if it has a more recent due time than
201 * the current "next" timer. We do this either by waking up the
202 * run thread, or explicitly setting the value in the manager.
204 #ifdef ISC_PLATFORM_USETHREADS
207 * This is a temporary (probably) hack to fix a bug on tru64 5.1
208 * and 5.1a. Sometimes, pthread_cond_timedwait() doesn't actually
209 * return when the time expires, so here, we check to see if
210 * we're 15 seconds or more behind, and if we are, we signal
211 * the dispatcher. This isn't such a bad idea as a general purpose
212 * watchdog, so perhaps we should just leave it in here.
214 if (signal_ok
&& timedwait
) {
215 isc_interval_t fifteen
;
218 isc_interval_set(&fifteen
, 15, 0);
219 result
= isc_time_add(&manager
->due
, &fifteen
, &then
);
221 if (result
== ISC_R_SUCCESS
&&
222 isc_time_compare(&then
, now
) < 0) {
223 SIGNAL(&manager
->wakeup
);
224 signal_ok
= ISC_FALSE
;
225 isc_log_write(isc_lctx
, ISC_LOGCATEGORY_GENERAL
,
226 ISC_LOGMODULE_TIMER
, ISC_LOG_WARNING
,
227 "*** POKED TIMER ***");
231 if (timer
->index
== 1 && signal_ok
) {
232 XTRACE(isc_msgcat_get(isc_msgcat
, ISC_MSGSET_TIMER
,
234 "signal (schedule)"));
235 SIGNAL(&manager
->wakeup
);
237 #else /* ISC_PLATFORM_USETHREADS */
238 if (timer
->index
== 1 &&
239 isc_time_compare(&timer
->due
, &manager
->due
) < 0)
240 manager
->due
= timer
->due
;
241 #endif /* ISC_PLATFORM_USETHREADS */
243 return (ISC_R_SUCCESS
);
247 deschedule(isc_timer_t
*timer
) {
248 isc_boolean_t need_wakeup
= ISC_FALSE
;
249 isc_timermgr_t
*manager
;
252 * The caller must ensure locking.
255 manager
= timer
->manager
;
256 if (timer
->index
> 0) {
257 if (timer
->index
== 1)
258 need_wakeup
= ISC_TRUE
;
259 isc_heap_delete(manager
->heap
, timer
->index
);
261 INSIST(manager
->nscheduled
> 0);
262 manager
->nscheduled
--;
263 #ifdef ISC_PLATFORM_USETHREADS
265 XTRACE(isc_msgcat_get(isc_msgcat
, ISC_MSGSET_TIMER
,
266 ISC_MSG_SIGNALDESCHED
,
267 "signal (deschedule)"));
268 SIGNAL(&manager
->wakeup
);
270 #endif /* ISC_PLATFORM_USETHREADS */
275 destroy(isc_timer_t
*timer
) {
276 isc_timermgr_t
*manager
= timer
->manager
;
279 * The caller must ensure it is safe to destroy the timer.
282 LOCK(&manager
->lock
);
284 (void)isc_task_purgerange(timer
->task
,
286 ISC_TIMEREVENT_FIRSTEVENT
,
287 ISC_TIMEREVENT_LASTEVENT
,
290 UNLINK(manager
->timers
, timer
, link
);
292 UNLOCK(&manager
->lock
);
294 isc_task_detach(&timer
->task
);
295 DESTROYLOCK(&timer
->lock
);
297 isc_mem_put(manager
->mctx
, timer
, sizeof(*timer
));
301 isc_timer_create(isc_timermgr_t
*manager
, isc_timertype_t type
,
302 isc_time_t
*expires
, isc_interval_t
*interval
,
303 isc_task_t
*task
, isc_taskaction_t action
, const void *arg
,
304 isc_timer_t
**timerp
)
311 * Create a new 'type' timer managed by 'manager'. The timers
312 * parameters are specified by 'expires' and 'interval'. Events
313 * will be posted to 'task' and when dispatched 'action' will be
314 * called with 'arg' as the arg value. The new timer is returned
318 REQUIRE(VALID_MANAGER(manager
));
319 REQUIRE(task
!= NULL
);
320 REQUIRE(action
!= NULL
);
322 expires
= isc_time_epoch
;
323 if (interval
== NULL
)
324 interval
= isc_interval_zero
;
325 REQUIRE(type
== isc_timertype_inactive
||
326 !(isc_time_isepoch(expires
) && isc_interval_iszero(interval
)));
327 REQUIRE(timerp
!= NULL
&& *timerp
== NULL
);
328 REQUIRE(type
!= isc_timertype_limited
||
329 !(isc_time_isepoch(expires
) || isc_interval_iszero(interval
)));
334 if (type
!= isc_timertype_inactive
) {
338 * We don't have to do this, but it keeps the compiler from
339 * complaining about "now" possibly being used without being
340 * set, even though it will never actually happen.
342 isc_time_settoepoch(&now
);
346 timer
= isc_mem_get(manager
->mctx
, sizeof(*timer
));
348 return (ISC_R_NOMEMORY
);
350 timer
->manager
= manager
;
351 timer
->references
= 1;
353 if (type
== isc_timertype_once
&& !isc_interval_iszero(interval
)) {
354 result
= isc_time_add(&now
, interval
, &timer
->idle
);
355 if (result
!= ISC_R_SUCCESS
) {
356 isc_mem_put(manager
->mctx
, timer
, sizeof(*timer
));
360 isc_time_settoepoch(&timer
->idle
);
363 timer
->expires
= *expires
;
364 timer
->interval
= *interval
;
366 isc_task_attach(task
, &timer
->task
);
367 timer
->action
= action
;
369 * Removing the const attribute from "arg" is the best of two
370 * evils here. If the timer->arg member is made const, then
371 * it affects a great many recipients of the timer event
372 * which did not pass in an "arg" that was truly const.
373 * Changing isc_timer_create() to not have "arg" prototyped as const,
374 * though, can cause compilers warnings for calls that *do*
375 * have a truly const arg. The caller will have to carefully
376 * keep track of whether arg started as a true const.
378 DE_CONST(arg
, timer
->arg
);
380 result
= isc_mutex_init(&timer
->lock
);
381 if (result
!= ISC_R_SUCCESS
) {
382 isc_task_detach(&timer
->task
);
383 isc_mem_put(manager
->mctx
, timer
, sizeof(*timer
));
386 ISC_LINK_INIT(timer
, link
);
387 timer
->magic
= TIMER_MAGIC
;
389 LOCK(&manager
->lock
);
392 * Note we don't have to lock the timer like we normally would because
393 * there are no external references to it yet.
396 if (type
!= isc_timertype_inactive
)
397 result
= schedule(timer
, &now
, ISC_TRUE
);
399 result
= ISC_R_SUCCESS
;
400 if (result
== ISC_R_SUCCESS
)
401 APPEND(manager
->timers
, timer
, link
);
403 UNLOCK(&manager
->lock
);
405 if (result
!= ISC_R_SUCCESS
) {
407 DESTROYLOCK(&timer
->lock
);
408 isc_task_detach(&timer
->task
);
409 isc_mem_put(manager
->mctx
, timer
, sizeof(*timer
));
415 return (ISC_R_SUCCESS
);
419 isc_timer_reset(isc_timer_t
*timer
, isc_timertype_t type
,
420 isc_time_t
*expires
, isc_interval_t
*interval
,
424 isc_timermgr_t
*manager
;
428 * Change the timer's type, expires, and interval values to the given
429 * values. If 'purge' is ISC_TRUE, any pending events from this timer
430 * are purged from its task's event queue.
433 REQUIRE(VALID_TIMER(timer
));
434 manager
= timer
->manager
;
435 REQUIRE(VALID_MANAGER(manager
));
437 expires
= isc_time_epoch
;
438 if (interval
== NULL
)
439 interval
= isc_interval_zero
;
440 REQUIRE(type
== isc_timertype_inactive
||
441 !(isc_time_isepoch(expires
) && isc_interval_iszero(interval
)));
442 REQUIRE(type
!= isc_timertype_limited
||
443 !(isc_time_isepoch(expires
) || isc_interval_iszero(interval
)));
448 if (type
!= isc_timertype_inactive
) {
452 * We don't have to do this, but it keeps the compiler from
453 * complaining about "now" possibly being used without being
454 * set, even though it will never actually happen.
456 isc_time_settoepoch(&now
);
459 manager
= timer
->manager
;
461 LOCK(&manager
->lock
);
465 (void)isc_task_purgerange(timer
->task
,
467 ISC_TIMEREVENT_FIRSTEVENT
,
468 ISC_TIMEREVENT_LASTEVENT
,
471 timer
->expires
= *expires
;
472 timer
->interval
= *interval
;
473 if (type
== isc_timertype_once
&& !isc_interval_iszero(interval
)) {
474 result
= isc_time_add(&now
, interval
, &timer
->idle
);
476 isc_time_settoepoch(&timer
->idle
);
477 result
= ISC_R_SUCCESS
;
480 if (result
== ISC_R_SUCCESS
) {
481 if (type
== isc_timertype_inactive
) {
483 result
= ISC_R_SUCCESS
;
485 result
= schedule(timer
, &now
, ISC_TRUE
);
488 UNLOCK(&timer
->lock
);
489 UNLOCK(&manager
->lock
);
495 isc_timer_gettype(isc_timer_t
*timer
) {
498 REQUIRE(VALID_TIMER(timer
));
502 UNLOCK(&timer
->lock
);
508 isc_timer_touch(isc_timer_t
*timer
) {
513 * Set the last-touched time of 'timer' to the current time.
516 REQUIRE(VALID_TIMER(timer
));
523 * REQUIRE(timer->type == isc_timertype_once);
525 * but we cannot without locking the manager lock too, which we
530 result
= isc_time_add(&now
, &timer
->interval
, &timer
->idle
);
532 UNLOCK(&timer
->lock
);
538 isc_timer_attach(isc_timer_t
*timer
, isc_timer_t
**timerp
) {
540 * Attach *timerp to timer.
543 REQUIRE(VALID_TIMER(timer
));
544 REQUIRE(timerp
!= NULL
&& *timerp
== NULL
);
548 UNLOCK(&timer
->lock
);
554 isc_timer_detach(isc_timer_t
**timerp
) {
556 isc_boolean_t free_timer
= ISC_FALSE
;
559 * Detach *timerp from its timer.
562 REQUIRE(timerp
!= NULL
);
564 REQUIRE(VALID_TIMER(timer
));
567 REQUIRE(timer
->references
> 0);
569 if (timer
->references
== 0)
570 free_timer
= ISC_TRUE
;
571 UNLOCK(&timer
->lock
);
580 dispatch(isc_timermgr_t
*manager
, isc_time_t
*now
) {
581 isc_boolean_t done
= ISC_FALSE
, post_event
, need_schedule
;
582 isc_timerevent_t
*event
;
583 isc_eventtype_t type
= 0;
589 * The caller must be holding the manager lock.
592 while (manager
->nscheduled
> 0 && !done
) {
593 timer
= isc_heap_element(manager
->heap
, 1);
594 INSIST(timer
->type
!= isc_timertype_inactive
);
595 if (isc_time_compare(now
, &timer
->due
) >= 0) {
596 if (timer
->type
== isc_timertype_ticker
) {
597 type
= ISC_TIMEREVENT_TICK
;
598 post_event
= ISC_TRUE
;
599 need_schedule
= ISC_TRUE
;
600 } else if (timer
->type
== isc_timertype_limited
) {
602 cmp
= isc_time_compare(now
, &timer
->expires
);
604 type
= ISC_TIMEREVENT_LIFE
;
605 post_event
= ISC_TRUE
;
606 need_schedule
= ISC_FALSE
;
608 type
= ISC_TIMEREVENT_TICK
;
609 post_event
= ISC_TRUE
;
610 need_schedule
= ISC_TRUE
;
612 } else if (!isc_time_isepoch(&timer
->expires
) &&
613 isc_time_compare(now
,
614 &timer
->expires
) >= 0) {
615 type
= ISC_TIMEREVENT_LIFE
;
616 post_event
= ISC_TRUE
;
617 need_schedule
= ISC_FALSE
;
622 if (!isc_time_isepoch(&timer
->idle
) &&
623 isc_time_compare(now
,
624 &timer
->idle
) >= 0) {
627 UNLOCK(&timer
->lock
);
629 type
= ISC_TIMEREVENT_IDLE
;
630 post_event
= ISC_TRUE
;
631 need_schedule
= ISC_FALSE
;
634 * Idle timer has been touched;
637 XTRACEID(isc_msgcat_get(isc_msgcat
,
642 post_event
= ISC_FALSE
;
643 need_schedule
= ISC_TRUE
;
648 XTRACEID(isc_msgcat_get(isc_msgcat
,
653 * XXX We could preallocate this event.
655 event
= (isc_timerevent_t
*)isc_event_allocate(manager
->mctx
,
663 event
->due
= timer
->due
;
664 isc_task_send(timer
->task
,
665 ISC_EVENT_PTR(&event
));
667 UNEXPECTED_ERROR(__FILE__
, __LINE__
, "%s",
668 isc_msgcat_get(isc_msgcat
,
670 ISC_MSG_EVENTNOTALLOC
,
676 isc_heap_delete(manager
->heap
, 1);
677 manager
->nscheduled
--;
680 result
= schedule(timer
, now
, ISC_FALSE
);
681 if (result
!= ISC_R_SUCCESS
)
682 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
684 isc_msgcat_get(isc_msgcat
,
692 manager
->due
= timer
->due
;
698 #ifdef ISC_PLATFORM_USETHREADS
699 static isc_threadresult_t
700 #ifdef _WIN32 /* XXXDCL */
704 isc_timermgr_t
*manager
= uap
;
708 LOCK(&manager
->lock
);
709 while (!manager
->done
) {
712 XTRACETIME(isc_msgcat_get(isc_msgcat
, ISC_MSGSET_GENERAL
,
716 dispatch(manager
, &now
);
718 if (manager
->nscheduled
> 0) {
719 XTRACETIME2(isc_msgcat_get(isc_msgcat
,
724 result
= WAITUNTIL(&manager
->wakeup
, &manager
->lock
, &manager
->due
);
725 INSIST(result
== ISC_R_SUCCESS
||
726 result
== ISC_R_TIMEDOUT
);
728 XTRACETIME(isc_msgcat_get(isc_msgcat
, ISC_MSGSET_GENERAL
,
729 ISC_MSG_WAIT
, "wait"), now
);
730 WAIT(&manager
->wakeup
, &manager
->lock
);
732 XTRACE(isc_msgcat_get(isc_msgcat
, ISC_MSGSET_TIMER
,
733 ISC_MSG_WAKEUP
, "wakeup"));
735 UNLOCK(&manager
->lock
);
737 return ((isc_threadresult_t
)0);
739 #endif /* ISC_PLATFORM_USETHREADS */
742 sooner(void *v1
, void *v2
) {
743 isc_timer_t
*t1
, *t2
;
747 REQUIRE(VALID_TIMER(t1
));
748 REQUIRE(VALID_TIMER(t2
));
750 if (isc_time_compare(&t1
->due
, &t2
->due
) < 0)
756 set_index(void *what
, unsigned int index
) {
760 REQUIRE(VALID_TIMER(timer
));
762 timer
->index
= index
;
766 isc_timermgr_create(isc_mem_t
*mctx
, isc_timermgr_t
**managerp
) {
767 isc_timermgr_t
*manager
;
771 * Create a timer manager.
774 REQUIRE(managerp
!= NULL
&& *managerp
== NULL
);
776 #ifndef ISC_PLATFORM_USETHREADS
777 if (timermgr
!= NULL
) {
779 *managerp
= timermgr
;
780 return (ISC_R_SUCCESS
);
782 #endif /* ISC_PLATFORM_USETHREADS */
784 manager
= isc_mem_get(mctx
, sizeof(*manager
));
786 return (ISC_R_NOMEMORY
);
788 manager
->magic
= TIMER_MANAGER_MAGIC
;
789 manager
->mctx
= NULL
;
790 manager
->done
= ISC_FALSE
;
791 INIT_LIST(manager
->timers
);
792 manager
->nscheduled
= 0;
793 isc_time_settoepoch(&manager
->due
);
794 manager
->heap
= NULL
;
795 result
= isc_heap_create(mctx
, sooner
, set_index
, 0, &manager
->heap
);
796 if (result
!= ISC_R_SUCCESS
) {
797 INSIST(result
== ISC_R_NOMEMORY
);
798 isc_mem_put(mctx
, manager
, sizeof(*manager
));
799 return (ISC_R_NOMEMORY
);
801 result
= isc_mutex_init(&manager
->lock
);
802 if (result
!= ISC_R_SUCCESS
) {
803 isc_heap_destroy(&manager
->heap
);
804 isc_mem_put(mctx
, manager
, sizeof(*manager
));
807 isc_mem_attach(mctx
, &manager
->mctx
);
808 #ifdef ISC_PLATFORM_USETHREADS
809 if (isc_condition_init(&manager
->wakeup
) != ISC_R_SUCCESS
) {
810 isc_mem_detach(&manager
->mctx
);
811 DESTROYLOCK(&manager
->lock
);
812 isc_heap_destroy(&manager
->heap
);
813 isc_mem_put(mctx
, manager
, sizeof(*manager
));
814 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
815 "isc_condition_init() %s",
816 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_GENERAL
,
817 ISC_MSG_FAILED
, "failed"));
818 return (ISC_R_UNEXPECTED
);
820 if (isc_thread_create(run
, manager
, &manager
->thread
) !=
822 isc_mem_detach(&manager
->mctx
);
823 (void)isc_condition_destroy(&manager
->wakeup
);
824 DESTROYLOCK(&manager
->lock
);
825 isc_heap_destroy(&manager
->heap
);
826 isc_mem_put(mctx
, manager
, sizeof(*manager
));
827 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
828 "isc_thread_create() %s",
829 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_GENERAL
,
830 ISC_MSG_FAILED
, "failed"));
831 return (ISC_R_UNEXPECTED
);
833 #else /* ISC_PLATFORM_USETHREADS */
836 #endif /* ISC_PLATFORM_USETHREADS */
840 return (ISC_R_SUCCESS
);
844 isc_timermgr_poke(isc_timermgr_t
*manager
) {
845 #ifdef ISC_PLATFORM_USETHREADS
846 REQUIRE(VALID_MANAGER(manager
));
848 SIGNAL(&manager
->wakeup
);
855 isc_timermgr_destroy(isc_timermgr_t
**managerp
) {
856 isc_timermgr_t
*manager
;
860 * Destroy a timer manager.
863 REQUIRE(managerp
!= NULL
);
865 REQUIRE(VALID_MANAGER(manager
));
867 LOCK(&manager
->lock
);
869 #ifndef ISC_PLATFORM_USETHREADS
870 if (manager
->refs
> 1) {
872 UNLOCK(&manager
->lock
);
877 isc__timermgr_dispatch();
878 #endif /* ISC_PLATFORM_USETHREADS */
880 REQUIRE(EMPTY(manager
->timers
));
881 manager
->done
= ISC_TRUE
;
883 #ifdef ISC_PLATFORM_USETHREADS
884 XTRACE(isc_msgcat_get(isc_msgcat
, ISC_MSGSET_TIMER
,
885 ISC_MSG_SIGNALDESTROY
, "signal (destroy)"));
886 SIGNAL(&manager
->wakeup
);
887 #endif /* ISC_PLATFORM_USETHREADS */
889 UNLOCK(&manager
->lock
);
891 #ifdef ISC_PLATFORM_USETHREADS
893 * Wait for thread to exit.
895 if (isc_thread_join(manager
->thread
, NULL
) != ISC_R_SUCCESS
)
896 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
897 "isc_thread_join() %s",
898 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_GENERAL
,
899 ISC_MSG_FAILED
, "failed"));
900 #endif /* ISC_PLATFORM_USETHREADS */
905 #ifdef ISC_PLATFORM_USETHREADS
906 (void)isc_condition_destroy(&manager
->wakeup
);
907 #endif /* ISC_PLATFORM_USETHREADS */
908 DESTROYLOCK(&manager
->lock
);
909 isc_heap_destroy(&manager
->heap
);
911 mctx
= manager
->mctx
;
912 isc_mem_put(mctx
, manager
, sizeof(*manager
));
913 isc_mem_detach(&mctx
);
918 #ifndef ISC_PLATFORM_USETHREADS
920 isc__timermgr_nextevent(isc_time_t
*when
) {
921 if (timermgr
== NULL
|| timermgr
->nscheduled
== 0)
922 return (ISC_R_NOTFOUND
);
923 *when
= timermgr
->due
;
924 return (ISC_R_SUCCESS
);
928 isc__timermgr_dispatch(void) {
930 if (timermgr
== NULL
)
933 dispatch(timermgr
, &now
);
935 #endif /* ISC_PLATFORM_USETHREADS */