2 * Copyright (C) 2004, 2005, 2007-2009 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.
18 /* $Id: timer.c,v 1.81.32.7 2009/01/23 23:46:44 tbox Exp $ */
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>
37 #ifndef ISC_PLATFORM_USETHREADS
39 #endif /* ISC_PLATFORM_USETHREADS */
41 #ifdef ISC_TIMER_TRACE
42 #define XTRACE(s) fprintf(stderr, "%s\n", (s))
43 #define XTRACEID(s, t) fprintf(stderr, "%s %p\n", (s), (t))
44 #define XTRACETIME(s, d) fprintf(stderr, "%s %u.%09u\n", (s), \
45 (d).seconds, (d).nanoseconds)
46 #define XTRACETIME2(s, d, n) fprintf(stderr, "%s %u.%09u %u.%09u\n", (s), \
47 (d).seconds, (d).nanoseconds, (n).seconds, (n).nanoseconds)
48 #define XTRACETIMER(s, t, d) fprintf(stderr, "%s %p %u.%09u\n", (s), (t), \
49 (d).seconds, (d).nanoseconds)
52 #define XTRACEID(s, t)
53 #define XTRACETIME(s, d)
54 #define XTRACETIME2(s, d, n)
55 #define XTRACETIMER(s, t, d)
56 #endif /* ISC_TIMER_TRACE */
58 #define TIMER_MAGIC ISC_MAGIC('T', 'I', 'M', 'R')
59 #define VALID_TIMER(t) ISC_MAGIC_VALID(t, TIMER_MAGIC)
64 isc_timermgr_t
* manager
;
66 /*! Locked by timer lock. */
67 unsigned int references
;
69 /*! Locked by manager lock. */
72 isc_interval_t interval
;
74 isc_taskaction_t action
;
78 LINK(isc_timer_t
) link
;
81 #define TIMER_MANAGER_MAGIC ISC_MAGIC('T', 'I', 'M', 'M')
82 #define VALID_MANAGER(m) ISC_MAGIC_VALID(m, TIMER_MANAGER_MAGIC)
89 /* Locked by manager lock. */
91 LIST(isc_timer_t
) timers
;
92 unsigned int nscheduled
;
94 #ifdef ISC_PLATFORM_USETHREADS
95 isc_condition_t wakeup
;
97 #else /* ISC_PLATFORM_USETHREADS */
99 #endif /* ISC_PLATFORM_USETHREADS */
103 #ifndef ISC_PLATFORM_USETHREADS
105 * If threads are not in use, there can be only one.
107 static isc_timermgr_t
*timermgr
= NULL
;
108 #endif /* ISC_PLATFORM_USETHREADS */
110 static inline isc_result_t
111 schedule(isc_timer_t
*timer
, isc_time_t
*now
, isc_boolean_t signal_ok
) {
113 isc_timermgr_t
*manager
;
116 #ifdef ISC_PLATFORM_USETHREADS
117 isc_boolean_t timedwait
;
121 * Note: the caller must ensure locking.
124 REQUIRE(timer
->type
!= isc_timertype_inactive
);
126 #ifndef ISC_PLATFORM_USETHREADS
128 #endif /* ISC_PLATFORM_USETHREADS */
130 manager
= timer
->manager
;
132 #ifdef ISC_PLATFORM_USETHREADS
134 * If the manager was timed wait, we may need to signal the
135 * manager to force a wakeup.
137 timedwait
= ISC_TF(manager
->nscheduled
> 0 &&
138 isc_time_seconds(&manager
->due
) != 0);
142 * Compute the new due time.
144 if (timer
->type
!= isc_timertype_once
) {
145 result
= isc_time_add(now
, &timer
->interval
, &due
);
146 if (result
!= ISC_R_SUCCESS
)
148 if (timer
->type
== isc_timertype_limited
&&
149 isc_time_compare(&timer
->expires
, &due
) < 0)
150 due
= timer
->expires
;
152 if (isc_time_isepoch(&timer
->idle
))
153 due
= timer
->expires
;
154 else if (isc_time_isepoch(&timer
->expires
))
156 else if (isc_time_compare(&timer
->idle
, &timer
->expires
) < 0)
159 due
= timer
->expires
;
163 * Schedule the timer.
166 if (timer
->index
> 0) {
170 cmp
= isc_time_compare(&due
, &timer
->due
);
174 isc_heap_increased(manager
->heap
, timer
->index
);
177 isc_heap_decreased(manager
->heap
, timer
->index
);
185 result
= isc_heap_insert(manager
->heap
, timer
);
186 if (result
!= ISC_R_SUCCESS
) {
187 INSIST(result
== ISC_R_NOMEMORY
);
188 return (ISC_R_NOMEMORY
);
190 manager
->nscheduled
++;
193 XTRACETIMER(isc_msgcat_get(isc_msgcat
, ISC_MSGSET_TIMER
,
194 ISC_MSG_SCHEDULE
, "schedule"), timer
, due
);
197 * If this timer is at the head of the queue, we need to ensure
198 * that we won't miss it if it has a more recent due time than
199 * the current "next" timer. We do this either by waking up the
200 * run thread, or explicitly setting the value in the manager.
202 #ifdef ISC_PLATFORM_USETHREADS
205 * This is a temporary (probably) hack to fix a bug on tru64 5.1
206 * and 5.1a. Sometimes, pthread_cond_timedwait() doesn't actually
207 * return when the time expires, so here, we check to see if
208 * we're 15 seconds or more behind, and if we are, we signal
209 * the dispatcher. This isn't such a bad idea as a general purpose
210 * watchdog, so perhaps we should just leave it in here.
212 if (signal_ok
&& timedwait
) {
213 isc_interval_t fifteen
;
216 isc_interval_set(&fifteen
, 15, 0);
217 result
= isc_time_add(&manager
->due
, &fifteen
, &then
);
219 if (result
== ISC_R_SUCCESS
&&
220 isc_time_compare(&then
, now
) < 0) {
221 SIGNAL(&manager
->wakeup
);
222 signal_ok
= ISC_FALSE
;
223 isc_log_write(isc_lctx
, ISC_LOGCATEGORY_GENERAL
,
224 ISC_LOGMODULE_TIMER
, ISC_LOG_WARNING
,
225 "*** POKED TIMER ***");
229 if (timer
->index
== 1 && signal_ok
) {
230 XTRACE(isc_msgcat_get(isc_msgcat
, ISC_MSGSET_TIMER
,
232 "signal (schedule)"));
233 SIGNAL(&manager
->wakeup
);
235 #else /* ISC_PLATFORM_USETHREADS */
236 if (timer
->index
== 1 &&
237 isc_time_compare(&timer
->due
, &manager
->due
) < 0)
238 manager
->due
= timer
->due
;
239 #endif /* ISC_PLATFORM_USETHREADS */
241 return (ISC_R_SUCCESS
);
245 deschedule(isc_timer_t
*timer
) {
246 isc_boolean_t need_wakeup
= ISC_FALSE
;
247 isc_timermgr_t
*manager
;
250 * The caller must ensure locking.
253 manager
= timer
->manager
;
254 if (timer
->index
> 0) {
255 if (timer
->index
== 1)
256 need_wakeup
= ISC_TRUE
;
257 isc_heap_delete(manager
->heap
, timer
->index
);
259 INSIST(manager
->nscheduled
> 0);
260 manager
->nscheduled
--;
261 #ifdef ISC_PLATFORM_USETHREADS
263 XTRACE(isc_msgcat_get(isc_msgcat
, ISC_MSGSET_TIMER
,
264 ISC_MSG_SIGNALDESCHED
,
265 "signal (deschedule)"));
266 SIGNAL(&manager
->wakeup
);
268 #endif /* ISC_PLATFORM_USETHREADS */
273 destroy(isc_timer_t
*timer
) {
274 isc_timermgr_t
*manager
= timer
->manager
;
277 * The caller must ensure it is safe to destroy the timer.
280 LOCK(&manager
->lock
);
282 (void)isc_task_purgerange(timer
->task
,
284 ISC_TIMEREVENT_FIRSTEVENT
,
285 ISC_TIMEREVENT_LASTEVENT
,
288 UNLINK(manager
->timers
, timer
, link
);
290 UNLOCK(&manager
->lock
);
292 isc_task_detach(&timer
->task
);
293 DESTROYLOCK(&timer
->lock
);
295 isc_mem_put(manager
->mctx
, timer
, sizeof(*timer
));
299 isc_timer_create(isc_timermgr_t
*manager
, isc_timertype_t type
,
300 isc_time_t
*expires
, isc_interval_t
*interval
,
301 isc_task_t
*task
, isc_taskaction_t action
, const void *arg
,
302 isc_timer_t
**timerp
)
309 * Create a new 'type' timer managed by 'manager'. The timers
310 * parameters are specified by 'expires' and 'interval'. Events
311 * will be posted to 'task' and when dispatched 'action' will be
312 * called with 'arg' as the arg value. The new timer is returned
316 REQUIRE(VALID_MANAGER(manager
));
317 REQUIRE(task
!= NULL
);
318 REQUIRE(action
!= NULL
);
320 expires
= isc_time_epoch
;
321 if (interval
== NULL
)
322 interval
= isc_interval_zero
;
323 REQUIRE(type
== isc_timertype_inactive
||
324 !(isc_time_isepoch(expires
) && isc_interval_iszero(interval
)));
325 REQUIRE(timerp
!= NULL
&& *timerp
== NULL
);
326 REQUIRE(type
!= isc_timertype_limited
||
327 !(isc_time_isepoch(expires
) || isc_interval_iszero(interval
)));
332 if (type
!= isc_timertype_inactive
) {
336 * We don't have to do this, but it keeps the compiler from
337 * complaining about "now" possibly being used without being
338 * set, even though it will never actually happen.
340 isc_time_settoepoch(&now
);
344 timer
= isc_mem_get(manager
->mctx
, sizeof(*timer
));
346 return (ISC_R_NOMEMORY
);
348 timer
->manager
= manager
;
349 timer
->references
= 1;
351 if (type
== isc_timertype_once
&& !isc_interval_iszero(interval
)) {
352 result
= isc_time_add(&now
, interval
, &timer
->idle
);
353 if (result
!= ISC_R_SUCCESS
) {
354 isc_mem_put(manager
->mctx
, timer
, sizeof(*timer
));
358 isc_time_settoepoch(&timer
->idle
);
361 timer
->expires
= *expires
;
362 timer
->interval
= *interval
;
364 isc_task_attach(task
, &timer
->task
);
365 timer
->action
= action
;
367 * Removing the const attribute from "arg" is the best of two
368 * evils here. If the timer->arg member is made const, then
369 * it affects a great many recipients of the timer event
370 * which did not pass in an "arg" that was truly const.
371 * Changing isc_timer_create() to not have "arg" prototyped as const,
372 * though, can cause compilers warnings for calls that *do*
373 * have a truly const arg. The caller will have to carefully
374 * keep track of whether arg started as a true const.
376 DE_CONST(arg
, timer
->arg
);
378 result
= isc_mutex_init(&timer
->lock
);
379 if (result
!= ISC_R_SUCCESS
) {
380 isc_task_detach(&timer
->task
);
381 isc_mem_put(manager
->mctx
, timer
, sizeof(*timer
));
384 ISC_LINK_INIT(timer
, link
);
385 timer
->magic
= TIMER_MAGIC
;
387 LOCK(&manager
->lock
);
390 * Note we don't have to lock the timer like we normally would because
391 * there are no external references to it yet.
394 if (type
!= isc_timertype_inactive
)
395 result
= schedule(timer
, &now
, ISC_TRUE
);
397 result
= ISC_R_SUCCESS
;
398 if (result
== ISC_R_SUCCESS
)
399 APPEND(manager
->timers
, timer
, link
);
401 UNLOCK(&manager
->lock
);
403 if (result
!= ISC_R_SUCCESS
) {
405 DESTROYLOCK(&timer
->lock
);
406 isc_task_detach(&timer
->task
);
407 isc_mem_put(manager
->mctx
, timer
, sizeof(*timer
));
413 return (ISC_R_SUCCESS
);
417 isc_timer_reset(isc_timer_t
*timer
, isc_timertype_t type
,
418 isc_time_t
*expires
, isc_interval_t
*interval
,
422 isc_timermgr_t
*manager
;
426 * Change the timer's type, expires, and interval values to the given
427 * values. If 'purge' is ISC_TRUE, any pending events from this timer
428 * are purged from its task's event queue.
431 REQUIRE(VALID_TIMER(timer
));
432 manager
= timer
->manager
;
433 REQUIRE(VALID_MANAGER(manager
));
435 expires
= isc_time_epoch
;
436 if (interval
== NULL
)
437 interval
= isc_interval_zero
;
438 REQUIRE(type
== isc_timertype_inactive
||
439 !(isc_time_isepoch(expires
) && isc_interval_iszero(interval
)));
440 REQUIRE(type
!= isc_timertype_limited
||
441 !(isc_time_isepoch(expires
) || isc_interval_iszero(interval
)));
446 if (type
!= isc_timertype_inactive
) {
450 * We don't have to do this, but it keeps the compiler from
451 * complaining about "now" possibly being used without being
452 * set, even though it will never actually happen.
454 isc_time_settoepoch(&now
);
457 manager
= timer
->manager
;
459 LOCK(&manager
->lock
);
463 (void)isc_task_purgerange(timer
->task
,
465 ISC_TIMEREVENT_FIRSTEVENT
,
466 ISC_TIMEREVENT_LASTEVENT
,
469 timer
->expires
= *expires
;
470 timer
->interval
= *interval
;
471 if (type
== isc_timertype_once
&& !isc_interval_iszero(interval
)) {
472 result
= isc_time_add(&now
, interval
, &timer
->idle
);
474 isc_time_settoepoch(&timer
->idle
);
475 result
= ISC_R_SUCCESS
;
478 if (result
== ISC_R_SUCCESS
) {
479 if (type
== isc_timertype_inactive
) {
481 result
= ISC_R_SUCCESS
;
483 result
= schedule(timer
, &now
, ISC_TRUE
);
486 UNLOCK(&timer
->lock
);
487 UNLOCK(&manager
->lock
);
493 isc_timer_gettype(isc_timer_t
*timer
) {
496 REQUIRE(VALID_TIMER(timer
));
500 UNLOCK(&timer
->lock
);
506 isc_timer_touch(isc_timer_t
*timer
) {
511 * Set the last-touched time of 'timer' to the current time.
514 REQUIRE(VALID_TIMER(timer
));
521 * REQUIRE(timer->type == isc_timertype_once);
523 * but we cannot without locking the manager lock too, which we
528 result
= isc_time_add(&now
, &timer
->interval
, &timer
->idle
);
530 UNLOCK(&timer
->lock
);
536 isc_timer_attach(isc_timer_t
*timer
, isc_timer_t
**timerp
) {
538 * Attach *timerp to timer.
541 REQUIRE(VALID_TIMER(timer
));
542 REQUIRE(timerp
!= NULL
&& *timerp
== NULL
);
546 UNLOCK(&timer
->lock
);
552 isc_timer_detach(isc_timer_t
**timerp
) {
554 isc_boolean_t free_timer
= ISC_FALSE
;
557 * Detach *timerp from its timer.
560 REQUIRE(timerp
!= NULL
);
562 REQUIRE(VALID_TIMER(timer
));
565 REQUIRE(timer
->references
> 0);
567 if (timer
->references
== 0)
568 free_timer
= ISC_TRUE
;
569 UNLOCK(&timer
->lock
);
578 dispatch(isc_timermgr_t
*manager
, isc_time_t
*now
) {
579 isc_boolean_t done
= ISC_FALSE
, post_event
, need_schedule
;
580 isc_timerevent_t
*event
;
581 isc_eventtype_t type
= 0;
587 * The caller must be holding the manager lock.
590 while (manager
->nscheduled
> 0 && !done
) {
591 timer
= isc_heap_element(manager
->heap
, 1);
592 INSIST(timer
->type
!= isc_timertype_inactive
);
593 if (isc_time_compare(now
, &timer
->due
) >= 0) {
594 if (timer
->type
== isc_timertype_ticker
) {
595 type
= ISC_TIMEREVENT_TICK
;
596 post_event
= ISC_TRUE
;
597 need_schedule
= ISC_TRUE
;
598 } else if (timer
->type
== isc_timertype_limited
) {
600 cmp
= isc_time_compare(now
, &timer
->expires
);
602 type
= ISC_TIMEREVENT_LIFE
;
603 post_event
= ISC_TRUE
;
604 need_schedule
= ISC_FALSE
;
606 type
= ISC_TIMEREVENT_TICK
;
607 post_event
= ISC_TRUE
;
608 need_schedule
= ISC_TRUE
;
610 } else if (!isc_time_isepoch(&timer
->expires
) &&
611 isc_time_compare(now
,
612 &timer
->expires
) >= 0) {
613 type
= ISC_TIMEREVENT_LIFE
;
614 post_event
= ISC_TRUE
;
615 need_schedule
= ISC_FALSE
;
620 if (!isc_time_isepoch(&timer
->idle
) &&
621 isc_time_compare(now
,
622 &timer
->idle
) >= 0) {
625 UNLOCK(&timer
->lock
);
627 type
= ISC_TIMEREVENT_IDLE
;
628 post_event
= ISC_TRUE
;
629 need_schedule
= ISC_FALSE
;
632 * Idle timer has been touched;
635 XTRACEID(isc_msgcat_get(isc_msgcat
,
640 post_event
= ISC_FALSE
;
641 need_schedule
= ISC_TRUE
;
646 XTRACEID(isc_msgcat_get(isc_msgcat
,
651 * XXX We could preallocate this event.
653 event
= (isc_timerevent_t
*)isc_event_allocate(manager
->mctx
,
661 event
->due
= timer
->due
;
662 isc_task_send(timer
->task
,
663 ISC_EVENT_PTR(&event
));
665 UNEXPECTED_ERROR(__FILE__
, __LINE__
, "%s",
666 isc_msgcat_get(isc_msgcat
,
668 ISC_MSG_EVENTNOTALLOC
,
674 isc_heap_delete(manager
->heap
, 1);
675 manager
->nscheduled
--;
678 result
= schedule(timer
, now
, ISC_FALSE
);
679 if (result
!= ISC_R_SUCCESS
)
680 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
682 isc_msgcat_get(isc_msgcat
,
690 manager
->due
= timer
->due
;
696 #ifdef ISC_PLATFORM_USETHREADS
697 static isc_threadresult_t
698 #ifdef _WIN32 /* XXXDCL */
702 isc_timermgr_t
*manager
= uap
;
706 LOCK(&manager
->lock
);
707 while (!manager
->done
) {
710 XTRACETIME(isc_msgcat_get(isc_msgcat
, ISC_MSGSET_GENERAL
,
714 dispatch(manager
, &now
);
716 if (manager
->nscheduled
> 0) {
717 XTRACETIME2(isc_msgcat_get(isc_msgcat
,
722 result
= WAITUNTIL(&manager
->wakeup
, &manager
->lock
, &manager
->due
);
723 INSIST(result
== ISC_R_SUCCESS
||
724 result
== ISC_R_TIMEDOUT
);
726 XTRACETIME(isc_msgcat_get(isc_msgcat
, ISC_MSGSET_GENERAL
,
727 ISC_MSG_WAIT
, "wait"), now
);
728 WAIT(&manager
->wakeup
, &manager
->lock
);
730 XTRACE(isc_msgcat_get(isc_msgcat
, ISC_MSGSET_TIMER
,
731 ISC_MSG_WAKEUP
, "wakeup"));
733 UNLOCK(&manager
->lock
);
735 return ((isc_threadresult_t
)0);
737 #endif /* ISC_PLATFORM_USETHREADS */
740 sooner(void *v1
, void *v2
) {
741 isc_timer_t
*t1
, *t2
;
745 REQUIRE(VALID_TIMER(t1
));
746 REQUIRE(VALID_TIMER(t2
));
748 if (isc_time_compare(&t1
->due
, &t2
->due
) < 0)
754 set_index(void *what
, unsigned int index
) {
758 REQUIRE(VALID_TIMER(timer
));
760 timer
->index
= index
;
764 isc_timermgr_create(isc_mem_t
*mctx
, isc_timermgr_t
**managerp
) {
765 isc_timermgr_t
*manager
;
769 * Create a timer manager.
772 REQUIRE(managerp
!= NULL
&& *managerp
== NULL
);
774 #ifndef ISC_PLATFORM_USETHREADS
775 if (timermgr
!= NULL
) {
777 *managerp
= timermgr
;
778 return (ISC_R_SUCCESS
);
780 #endif /* ISC_PLATFORM_USETHREADS */
782 manager
= isc_mem_get(mctx
, sizeof(*manager
));
784 return (ISC_R_NOMEMORY
);
786 manager
->magic
= TIMER_MANAGER_MAGIC
;
787 manager
->mctx
= NULL
;
788 manager
->done
= ISC_FALSE
;
789 INIT_LIST(manager
->timers
);
790 manager
->nscheduled
= 0;
791 isc_time_settoepoch(&manager
->due
);
792 manager
->heap
= NULL
;
793 result
= isc_heap_create(mctx
, sooner
, set_index
, 0, &manager
->heap
);
794 if (result
!= ISC_R_SUCCESS
) {
795 INSIST(result
== ISC_R_NOMEMORY
);
796 isc_mem_put(mctx
, manager
, sizeof(*manager
));
797 return (ISC_R_NOMEMORY
);
799 result
= isc_mutex_init(&manager
->lock
);
800 if (result
!= ISC_R_SUCCESS
) {
801 isc_heap_destroy(&manager
->heap
);
802 isc_mem_put(mctx
, manager
, sizeof(*manager
));
805 isc_mem_attach(mctx
, &manager
->mctx
);
806 #ifdef ISC_PLATFORM_USETHREADS
807 if (isc_condition_init(&manager
->wakeup
) != ISC_R_SUCCESS
) {
808 isc_mem_detach(&manager
->mctx
);
809 DESTROYLOCK(&manager
->lock
);
810 isc_heap_destroy(&manager
->heap
);
811 isc_mem_put(mctx
, manager
, sizeof(*manager
));
812 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
813 "isc_condition_init() %s",
814 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_GENERAL
,
815 ISC_MSG_FAILED
, "failed"));
816 return (ISC_R_UNEXPECTED
);
818 if (isc_thread_create(run
, manager
, &manager
->thread
) !=
820 isc_mem_detach(&manager
->mctx
);
821 (void)isc_condition_destroy(&manager
->wakeup
);
822 DESTROYLOCK(&manager
->lock
);
823 isc_heap_destroy(&manager
->heap
);
824 isc_mem_put(mctx
, manager
, sizeof(*manager
));
825 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
826 "isc_thread_create() %s",
827 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_GENERAL
,
828 ISC_MSG_FAILED
, "failed"));
829 return (ISC_R_UNEXPECTED
);
831 #else /* ISC_PLATFORM_USETHREADS */
834 #endif /* ISC_PLATFORM_USETHREADS */
838 return (ISC_R_SUCCESS
);
842 isc_timermgr_poke(isc_timermgr_t
*manager
) {
843 #ifdef ISC_PLATFORM_USETHREADS
844 REQUIRE(VALID_MANAGER(manager
));
846 SIGNAL(&manager
->wakeup
);
853 isc_timermgr_destroy(isc_timermgr_t
**managerp
) {
854 isc_timermgr_t
*manager
;
858 * Destroy a timer manager.
861 REQUIRE(managerp
!= NULL
);
863 REQUIRE(VALID_MANAGER(manager
));
865 LOCK(&manager
->lock
);
867 #ifndef ISC_PLATFORM_USETHREADS
868 if (manager
->refs
> 1) {
870 UNLOCK(&manager
->lock
);
875 isc__timermgr_dispatch();
876 #endif /* ISC_PLATFORM_USETHREADS */
878 REQUIRE(EMPTY(manager
->timers
));
879 manager
->done
= ISC_TRUE
;
881 #ifdef ISC_PLATFORM_USETHREADS
882 XTRACE(isc_msgcat_get(isc_msgcat
, ISC_MSGSET_TIMER
,
883 ISC_MSG_SIGNALDESTROY
, "signal (destroy)"));
884 SIGNAL(&manager
->wakeup
);
885 #endif /* ISC_PLATFORM_USETHREADS */
887 UNLOCK(&manager
->lock
);
889 #ifdef ISC_PLATFORM_USETHREADS
891 * Wait for thread to exit.
893 if (isc_thread_join(manager
->thread
, NULL
) != ISC_R_SUCCESS
)
894 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
895 "isc_thread_join() %s",
896 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_GENERAL
,
897 ISC_MSG_FAILED
, "failed"));
898 #endif /* ISC_PLATFORM_USETHREADS */
903 #ifdef ISC_PLATFORM_USETHREADS
904 (void)isc_condition_destroy(&manager
->wakeup
);
905 #endif /* ISC_PLATFORM_USETHREADS */
906 DESTROYLOCK(&manager
->lock
);
907 isc_heap_destroy(&manager
->heap
);
909 mctx
= manager
->mctx
;
910 isc_mem_put(mctx
, manager
, sizeof(*manager
));
911 isc_mem_detach(&mctx
);
916 #ifndef ISC_PLATFORM_USETHREADS
918 isc__timermgr_nextevent(isc_time_t
*when
) {
919 if (timermgr
== NULL
|| timermgr
->nscheduled
== 0)
920 return (ISC_R_NOTFOUND
);
921 *when
= timermgr
->due
;
922 return (ISC_R_SUCCESS
);
926 isc__timermgr_dispatch(void) {
928 if (timermgr
== NULL
)
931 dispatch(timermgr
, &now
);
933 #endif /* ISC_PLATFORM_USETHREADS */