xref: /openbsd/usr.bin/dig/lib/isc/timer.c (revision ad5cf538)
15185a700Sflorian /*
25185a700Sflorian  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
35185a700Sflorian  *
45185a700Sflorian  * Permission to use, copy, modify, and/or distribute this software for any
55185a700Sflorian  * purpose with or without fee is hereby granted, provided that the above
65185a700Sflorian  * copyright notice and this permission notice appear in all copies.
75185a700Sflorian  *
85185a700Sflorian  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
95185a700Sflorian  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
105185a700Sflorian  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
115185a700Sflorian  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
125185a700Sflorian  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
135185a700Sflorian  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
145185a700Sflorian  * PERFORMANCE OF THIS SOFTWARE.
155185a700Sflorian  */
165185a700Sflorian 
17*ad5cf538Sjung /* $Id: timer.c,v 1.21 2020/02/22 19:50:05 jung Exp $ */
185185a700Sflorian 
195185a700Sflorian /*! \file */
205185a700Sflorian 
215185a700Sflorian 
225185a700Sflorian #include <stdlib.h>
235185a700Sflorian #include <isc/heap.h>
245185a700Sflorian #include <isc/task.h>
255185a700Sflorian #include <isc/time.h>
265185a700Sflorian #include <isc/timer.h>
275185a700Sflorian #include <isc/util.h>
285185a700Sflorian 
295185a700Sflorian #include "timer_p.h"
305185a700Sflorian 
318b553854Sflorian typedef struct isc_timer isc_timer_t;
328b553854Sflorian typedef struct isc_timermgr isc_timermgr_t;
335185a700Sflorian 
348b553854Sflorian struct isc_timer {
355185a700Sflorian 	/*! Not locked. */
368b553854Sflorian 	isc_timermgr_t *		manager;
375185a700Sflorian 	/*! Locked by timer lock. */
385185a700Sflorian 	unsigned int			references;
397238a213Sflorian 	struct timespec			idle;
405185a700Sflorian 	/*! Locked by manager lock. */
417238a213Sflorian 	struct timespec			interval;
425185a700Sflorian 	isc_task_t *			task;
435185a700Sflorian 	isc_taskaction_t		action;
445185a700Sflorian 	void *				arg;
455185a700Sflorian 	unsigned int			index;
467238a213Sflorian 	struct timespec			due;
478b553854Sflorian 	LINK(isc_timer_t)		link;
485185a700Sflorian };
495185a700Sflorian 
508b553854Sflorian struct isc_timermgr {
515185a700Sflorian 	/* Not locked. */
525185a700Sflorian 	/* Locked by manager lock. */
535185a700Sflorian 	isc_boolean_t			done;
548b553854Sflorian 	LIST(isc_timer_t)		timers;
555185a700Sflorian 	unsigned int			nscheduled;
567238a213Sflorian 	struct timespec			due;
575185a700Sflorian 	unsigned int			refs;
585185a700Sflorian 	isc_heap_t *			heap;
595185a700Sflorian };
605185a700Sflorian 
615185a700Sflorian /*%
625185a700Sflorian  * The following are intended for internal use (indicated by "isc__"
635185a700Sflorian  * prefix) but are not declared as static, allowing direct access from
645185a700Sflorian  * unit tests etc.
655185a700Sflorian  */
665185a700Sflorian 
675185a700Sflorian /*!
685185a700Sflorian  * If the manager is supposed to be shared, there can be only one.
695185a700Sflorian  */
708b553854Sflorian static isc_timermgr_t *timermgr = NULL;
715185a700Sflorian 
725185a700Sflorian static inline isc_result_t
73*ad5cf538Sjung schedule(isc_timer_t *timer) {
745185a700Sflorian 	isc_result_t result;
758b553854Sflorian 	isc_timermgr_t *manager;
767238a213Sflorian 	struct timespec due;
775185a700Sflorian 
785185a700Sflorian 	/*!
795185a700Sflorian 	 * Note: the caller must ensure locking.
805185a700Sflorian 	 */
815185a700Sflorian 
825185a700Sflorian 	manager = timer->manager;
835185a700Sflorian 
845185a700Sflorian 	/*
855185a700Sflorian 	 * Compute the new due time.
865185a700Sflorian 	 */
875185a700Sflorian 	due = timer->idle;
885185a700Sflorian 
895185a700Sflorian 	/*
905185a700Sflorian 	 * Schedule the timer.
915185a700Sflorian 	 */
925185a700Sflorian 
935185a700Sflorian 	if (timer->index > 0) {
945185a700Sflorian 		/*
955185a700Sflorian 		 * Already scheduled.
965185a700Sflorian 		 */
97ba6f4614Sflorian 		if (timespeccmp(&due, &timer->due, <))
985185a700Sflorian 		    isc_heap_increased(manager->heap, timer->index);
99ba6f4614Sflorian 		else if (timespeccmp(&due, &timer->due, >))
1005185a700Sflorian 		    isc_heap_decreased(manager->heap, timer->index);
101ba6f4614Sflorian 
102ba6f4614Sflorian 		timer->due = due;
1035185a700Sflorian 	} else {
1045185a700Sflorian 		timer->due = due;
1055185a700Sflorian 		result = isc_heap_insert(manager->heap, timer);
1065185a700Sflorian 		if (result != ISC_R_SUCCESS) {
1075185a700Sflorian 			INSIST(result == ISC_R_NOMEMORY);
1085185a700Sflorian 			return (ISC_R_NOMEMORY);
1095185a700Sflorian 		}
1105185a700Sflorian 		manager->nscheduled++;
1115185a700Sflorian 	}
1125185a700Sflorian 
1135185a700Sflorian 	/*
1145185a700Sflorian 	 * If this timer is at the head of the queue, we need to ensure
1155185a700Sflorian 	 * that we won't miss it if it has a more recent due time than
1165185a700Sflorian 	 * the current "next" timer.  We do this either by waking up the
1175185a700Sflorian 	 * run thread, or explicitly setting the value in the manager.
1185185a700Sflorian 	 */
119ba6f4614Sflorian 	if (timer->index == 1 && timespeccmp(&timer->due, &manager->due, <))
1205185a700Sflorian 		manager->due = timer->due;
1215185a700Sflorian 
1225185a700Sflorian 	return (ISC_R_SUCCESS);
1235185a700Sflorian }
1245185a700Sflorian 
1255185a700Sflorian static inline void
1268b553854Sflorian deschedule(isc_timer_t *timer) {
1278b553854Sflorian 	isc_timermgr_t *manager;
1285185a700Sflorian 
1295185a700Sflorian 	/*
1305185a700Sflorian 	 * The caller must ensure locking.
1315185a700Sflorian 	 */
1325185a700Sflorian 
1335185a700Sflorian 	manager = timer->manager;
1345185a700Sflorian 	if (timer->index > 0) {
1355185a700Sflorian 		isc_heap_delete(manager->heap, timer->index);
1365185a700Sflorian 		timer->index = 0;
1375185a700Sflorian 		INSIST(manager->nscheduled > 0);
1385185a700Sflorian 		manager->nscheduled--;
1395185a700Sflorian 	}
1405185a700Sflorian }
1415185a700Sflorian 
1425185a700Sflorian static void
1438b553854Sflorian destroy(isc_timer_t *timer) {
1448b553854Sflorian 	isc_timermgr_t *manager = timer->manager;
1455185a700Sflorian 
1465185a700Sflorian 	/*
1475185a700Sflorian 	 * The caller must ensure it is safe to destroy the timer.
1485185a700Sflorian 	 */
1495185a700Sflorian 
1505185a700Sflorian 	(void)isc_task_purgerange(timer->task,
1515185a700Sflorian 				  timer,
1525185a700Sflorian 				  ISC_TIMEREVENT_FIRSTEVENT,
1535185a700Sflorian 				  ISC_TIMEREVENT_LASTEVENT,
1545185a700Sflorian 				  NULL);
1555185a700Sflorian 	deschedule(timer);
1565185a700Sflorian 	UNLINK(manager->timers, timer, link);
1575185a700Sflorian 
1585185a700Sflorian 	isc_task_detach(&timer->task);
1595185a700Sflorian 	free(timer);
1605185a700Sflorian }
1615185a700Sflorian 
1625185a700Sflorian isc_result_t
1638b553854Sflorian isc_timer_create(isc_timermgr_t *manager0, const struct timespec *interval,
1645185a700Sflorian 		  isc_task_t *task, isc_taskaction_t action, void *arg,
1655185a700Sflorian 		  isc_timer_t **timerp)
1665185a700Sflorian {
1678b553854Sflorian 	isc_timermgr_t *manager = (isc_timermgr_t *)manager0;
1688b553854Sflorian 	isc_timer_t *timer;
1695185a700Sflorian 	isc_result_t result;
1707238a213Sflorian 	struct timespec now;
1715185a700Sflorian 
1725185a700Sflorian 	/*
1735185a700Sflorian 	 * Create a new 'type' timer managed by 'manager'.  The timers
1745ec36317Sflorian 	 * parameters are specified by 'interval'.  Events
1755185a700Sflorian 	 * will be posted to 'task' and when dispatched 'action' will be
1765185a700Sflorian 	 * called with 'arg' as the arg value.  The new timer is returned
1775185a700Sflorian 	 * in 'timerp'.
1785185a700Sflorian 	 */
1795185a700Sflorian 
1805185a700Sflorian 	REQUIRE(task != NULL);
1815185a700Sflorian 	REQUIRE(action != NULL);
1821eb893f3Sflorian 	REQUIRE(interval != NULL);
183396be909Sflorian 	REQUIRE(timespecisset(interval));
1845185a700Sflorian 	REQUIRE(timerp != NULL && *timerp == NULL);
1855185a700Sflorian 
1865185a700Sflorian 	/*
1875185a700Sflorian 	 * Get current time.
1885185a700Sflorian 	 */
189b53d8310Sflorian 	clock_gettime(CLOCK_MONOTONIC, &now);
1905185a700Sflorian 
1915185a700Sflorian 	timer = malloc(sizeof(*timer));
1925185a700Sflorian 	if (timer == NULL)
1935185a700Sflorian 		return (ISC_R_NOMEMORY);
1945185a700Sflorian 
1955185a700Sflorian 	timer->manager = manager;
1965185a700Sflorian 	timer->references = 1;
1975185a700Sflorian 
198ffbbf1a1Sflorian 	if (timespecisset(interval))
199ffbbf1a1Sflorian 		timespecadd(&now, interval, &timer->idle);
2005185a700Sflorian 
2015185a700Sflorian 	timer->interval = *interval;
2025185a700Sflorian 	timer->task = NULL;
2035185a700Sflorian 	isc_task_attach(task, &timer->task);
2045185a700Sflorian 	timer->action = action;
2055185a700Sflorian 	/*
2065185a700Sflorian 	 * Removing the const attribute from "arg" is the best of two
2075185a700Sflorian 	 * evils here.  If the timer->arg member is made const, then
2085185a700Sflorian 	 * it affects a great many recipients of the timer event
2095185a700Sflorian 	 * which did not pass in an "arg" that was truly const.
2105185a700Sflorian 	 * Changing isc_timer_create() to not have "arg" prototyped as const,
2115185a700Sflorian 	 * though, can cause compilers warnings for calls that *do*
2125185a700Sflorian 	 * have a truly const arg.  The caller will have to carefully
2135185a700Sflorian 	 * keep track of whether arg started as a true const.
2145185a700Sflorian 	 */
2155185a700Sflorian 	DE_CONST(arg, timer->arg);
2165185a700Sflorian 	timer->index = 0;
2175185a700Sflorian 	ISC_LINK_INIT(timer, link);
2185185a700Sflorian 
219*ad5cf538Sjung 	result = schedule(timer);
2205185a700Sflorian 	if (result == ISC_R_SUCCESS)
2215185a700Sflorian 		APPEND(manager->timers, timer, link);
2225185a700Sflorian 
2235185a700Sflorian 	if (result != ISC_R_SUCCESS) {
2245185a700Sflorian 		isc_task_detach(&timer->task);
2255185a700Sflorian 		free(timer);
2265185a700Sflorian 		return (result);
2275185a700Sflorian 	}
2285185a700Sflorian 
2295185a700Sflorian 	*timerp = (isc_timer_t *)timer;
2305185a700Sflorian 
2315185a700Sflorian 	return (ISC_R_SUCCESS);
2325185a700Sflorian }
2335185a700Sflorian 
2345185a700Sflorian isc_result_t
2358b553854Sflorian isc_timer_reset(isc_timer_t *timer, const struct timespec *interval,
2365185a700Sflorian 		 isc_boolean_t purge)
2375185a700Sflorian {
2387238a213Sflorian 	struct timespec now;
2395185a700Sflorian 	isc_result_t result;
2405185a700Sflorian 
2415185a700Sflorian 	/*
2425185a700Sflorian 	 * Change the timer's type, expires, and interval values to the given
2435185a700Sflorian 	 * values.  If 'purge' is ISC_TRUE, any pending events from this timer
2445185a700Sflorian 	 * are purged from its task's event queue.
2455185a700Sflorian 	 */
2465185a700Sflorian 
2471eb893f3Sflorian 	REQUIRE(interval != NULL);
248396be909Sflorian 	REQUIRE(timespecisset(interval));
2495185a700Sflorian 
2505185a700Sflorian 	/*
2515185a700Sflorian 	 * Get current time.
2525185a700Sflorian 	 */
253b53d8310Sflorian 	clock_gettime(CLOCK_MONOTONIC, &now);
2545185a700Sflorian 
2555185a700Sflorian 	if (purge)
2565185a700Sflorian 		(void)isc_task_purgerange(timer->task,
2575185a700Sflorian 					  timer,
2585185a700Sflorian 					  ISC_TIMEREVENT_FIRSTEVENT,
2595185a700Sflorian 					  ISC_TIMEREVENT_LASTEVENT,
2605185a700Sflorian 					  NULL);
2615185a700Sflorian 	timer->interval = *interval;
262396be909Sflorian 	if (timespecisset(interval)) {
263ffbbf1a1Sflorian 		timespecadd(&now, interval, &timer->idle);
2645185a700Sflorian 	} else {
265bb7ec108Sflorian 		timespecclear(&timer->idle);
2665185a700Sflorian 	}
2675185a700Sflorian 
268*ad5cf538Sjung 	result = schedule(timer);
2695185a700Sflorian 
2705185a700Sflorian 	return (result);
2715185a700Sflorian }
2725185a700Sflorian 
273ffbbf1a1Sflorian void
2748b553854Sflorian isc_timer_touch(isc_timer_t *timer) {
2757238a213Sflorian 	struct timespec now;
2765185a700Sflorian 
2775185a700Sflorian 	/*
2785185a700Sflorian 	 * Set the last-touched time of 'timer' to the current time.
2795185a700Sflorian 	 */
2805185a700Sflorian 
2815185a700Sflorian 
282b53d8310Sflorian 	clock_gettime(CLOCK_MONOTONIC, &now);
283ffbbf1a1Sflorian 	timespecadd(&now, &timer->interval, &timer->idle);
2845185a700Sflorian }
2855185a700Sflorian 
2865185a700Sflorian void
2878b553854Sflorian isc_timer_detach(isc_timer_t **timerp) {
2888b553854Sflorian 	isc_timer_t *timer;
2895185a700Sflorian 	isc_boolean_t free_timer = ISC_FALSE;
2905185a700Sflorian 
2915185a700Sflorian 	/*
2925185a700Sflorian 	 * Detach *timerp from its timer.
2935185a700Sflorian 	 */
2945185a700Sflorian 
2955185a700Sflorian 	REQUIRE(timerp != NULL);
2968b553854Sflorian 	timer = (isc_timer_t *)*timerp;
2975185a700Sflorian 
2985185a700Sflorian 	REQUIRE(timer->references > 0);
2995185a700Sflorian 	timer->references--;
3005185a700Sflorian 	if (timer->references == 0)
3015185a700Sflorian 		free_timer = ISC_TRUE;
3025185a700Sflorian 
3035185a700Sflorian 	if (free_timer)
3045185a700Sflorian 		destroy(timer);
3055185a700Sflorian 
3065185a700Sflorian 	*timerp = NULL;
3075185a700Sflorian }
3085185a700Sflorian 
3095185a700Sflorian static void
3108b553854Sflorian dispatch(isc_timermgr_t *manager, struct timespec *now) {
3115185a700Sflorian 	isc_boolean_t done = ISC_FALSE, post_event, need_schedule;
3125185a700Sflorian 	isc_timerevent_t *event;
3135185a700Sflorian 	isc_eventtype_t type = 0;
3148b553854Sflorian 	isc_timer_t *timer;
3155185a700Sflorian 	isc_result_t result;
3165185a700Sflorian 	isc_boolean_t idle;
3175185a700Sflorian 
3185185a700Sflorian 	/*!
3195185a700Sflorian 	 * The caller must be holding the manager lock.
3205185a700Sflorian 	 */
3215185a700Sflorian 
3225185a700Sflorian 	while (manager->nscheduled > 0 && !done) {
3235185a700Sflorian 		timer = isc_heap_element(manager->heap, 1);
32475fe954bSflorian 		INSIST(timer != NULL);
325ba6f4614Sflorian 		if (timespeccmp(now, &timer->due, >=)) {
3265185a700Sflorian 			idle = ISC_FALSE;
3275185a700Sflorian 
328ba6f4614Sflorian 			if (timespecisset(&timer->idle) && timespeccmp(now,
329ba6f4614Sflorian 			    &timer->idle, >=)) {
3305185a700Sflorian 				idle = ISC_TRUE;
3315185a700Sflorian 			}
3325185a700Sflorian 			if (idle) {
3335185a700Sflorian 				type = ISC_TIMEREVENT_IDLE;
3345185a700Sflorian 				post_event = ISC_TRUE;
3355185a700Sflorian 				need_schedule = ISC_FALSE;
3365185a700Sflorian 			} else {
3375185a700Sflorian 				/*
3385185a700Sflorian 				 * Idle timer has been touched;
3395185a700Sflorian 				 * reschedule.
3405185a700Sflorian 				 */
3415185a700Sflorian 				post_event = ISC_FALSE;
3425185a700Sflorian 				need_schedule = ISC_TRUE;
3435185a700Sflorian 			}
3445185a700Sflorian 
3455185a700Sflorian 			if (post_event) {
3465185a700Sflorian 				/*
3475185a700Sflorian 				 * XXX We could preallocate this event.
3485185a700Sflorian 				 */
3495185a700Sflorian 				event = (isc_timerevent_t *)isc_event_allocate(
3505185a700Sflorian 							   timer,
3515185a700Sflorian 							   type,
3525185a700Sflorian 							   timer->action,
3535185a700Sflorian 							   timer->arg,
3545185a700Sflorian 							   sizeof(*event));
3555185a700Sflorian 
3565185a700Sflorian 				if (event != NULL) {
3575185a700Sflorian 					event->due = timer->due;
3585185a700Sflorian 					isc_task_send(timer->task,
3595185a700Sflorian 						      ISC_EVENT_PTR(&event));
3605185a700Sflorian 				} else
3615185a700Sflorian 					UNEXPECTED_ERROR(__FILE__, __LINE__, "%s",
3625185a700Sflorian 						 "couldn't allocate event");
3635185a700Sflorian 			}
3645185a700Sflorian 
3655185a700Sflorian 			timer->index = 0;
3665185a700Sflorian 			isc_heap_delete(manager->heap, 1);
3675185a700Sflorian 			manager->nscheduled--;
3685185a700Sflorian 
3695185a700Sflorian 			if (need_schedule) {
370*ad5cf538Sjung 				result = schedule(timer);
3715185a700Sflorian 				if (result != ISC_R_SUCCESS)
3725185a700Sflorian 					UNEXPECTED_ERROR(__FILE__, __LINE__,
3735185a700Sflorian 						"%s: %u",
3745185a700Sflorian 						"couldn't schedule timer",
3755185a700Sflorian 						result);
3765185a700Sflorian 			}
3775185a700Sflorian 		} else {
3785185a700Sflorian 			manager->due = timer->due;
3795185a700Sflorian 			done = ISC_TRUE;
3805185a700Sflorian 		}
3815185a700Sflorian 	}
3825185a700Sflorian }
3835185a700Sflorian 
3845185a700Sflorian static isc_boolean_t
3855185a700Sflorian sooner(void *v1, void *v2) {
3868b553854Sflorian 	isc_timer_t *t1, *t2;
3875185a700Sflorian 
3885185a700Sflorian 	t1 = v1;
3895185a700Sflorian 	t2 = v2;
3905185a700Sflorian 
391ba6f4614Sflorian 	if (timespeccmp(&t1->due, &t2->due, <))
3925185a700Sflorian 		return (ISC_TRUE);
3935185a700Sflorian 	return (ISC_FALSE);
3945185a700Sflorian }
3955185a700Sflorian 
3965185a700Sflorian static void
3975185a700Sflorian set_index(void *what, unsigned int index) {
3988b553854Sflorian 	isc_timer_t *timer;
3995185a700Sflorian 
4005185a700Sflorian 	timer = what;
4015185a700Sflorian 
4025185a700Sflorian 	timer->index = index;
4035185a700Sflorian }
4045185a700Sflorian 
4055185a700Sflorian isc_result_t
4068b553854Sflorian isc_timermgr_create(isc_timermgr_t **managerp) {
4078b553854Sflorian 	isc_timermgr_t *manager;
4085185a700Sflorian 	isc_result_t result;
4095185a700Sflorian 
4105185a700Sflorian 	/*
4115185a700Sflorian 	 * Create a timer manager.
4125185a700Sflorian 	 */
4135185a700Sflorian 
4145185a700Sflorian 	REQUIRE(managerp != NULL && *managerp == NULL);
4155185a700Sflorian 
4165185a700Sflorian 	if (timermgr != NULL) {
4175185a700Sflorian 		timermgr->refs++;
4185185a700Sflorian 		*managerp = (isc_timermgr_t *)timermgr;
4195185a700Sflorian 		return (ISC_R_SUCCESS);
4205185a700Sflorian 	}
4215185a700Sflorian 
4225185a700Sflorian 	manager = malloc(sizeof(*manager));
4235185a700Sflorian 	if (manager == NULL)
4245185a700Sflorian 		return (ISC_R_NOMEMORY);
4255185a700Sflorian 
4265185a700Sflorian 	manager->done = ISC_FALSE;
4275185a700Sflorian 	INIT_LIST(manager->timers);
4285185a700Sflorian 	manager->nscheduled = 0;
429bb7ec108Sflorian 	timespecclear(&manager->due);
4305185a700Sflorian 	manager->heap = NULL;
4315185a700Sflorian 	result = isc_heap_create(sooner, set_index, 0, &manager->heap);
4325185a700Sflorian 	if (result != ISC_R_SUCCESS) {
4335185a700Sflorian 		INSIST(result == ISC_R_NOMEMORY);
4345185a700Sflorian 		free(manager);
4355185a700Sflorian 		return (ISC_R_NOMEMORY);
4365185a700Sflorian 	}
4375185a700Sflorian 	manager->refs = 1;
4385185a700Sflorian 	timermgr = manager;
4395185a700Sflorian 
4405185a700Sflorian 	*managerp = (isc_timermgr_t *)manager;
4415185a700Sflorian 
4425185a700Sflorian 	return (ISC_R_SUCCESS);
4435185a700Sflorian }
4445185a700Sflorian 
4455185a700Sflorian void
4468b553854Sflorian isc_timermgr_destroy(isc_timermgr_t **managerp) {
4478b553854Sflorian 	isc_timermgr_t *manager;
4485185a700Sflorian 
4495185a700Sflorian 	/*
4505185a700Sflorian 	 * Destroy a timer manager.
4515185a700Sflorian 	 */
4525185a700Sflorian 
4535185a700Sflorian 	REQUIRE(managerp != NULL);
4548b553854Sflorian 	manager = (isc_timermgr_t *)*managerp;
4555185a700Sflorian 
4565185a700Sflorian 	manager->refs--;
4575185a700Sflorian 	if (manager->refs > 0) {
4585185a700Sflorian 		*managerp = NULL;
4595185a700Sflorian 		return;
4605185a700Sflorian 	}
4615185a700Sflorian 	timermgr = NULL;
4625185a700Sflorian 
4638b553854Sflorian 	isc_timermgr_dispatch((isc_timermgr_t *)manager);
4645185a700Sflorian 
4655185a700Sflorian 	REQUIRE(EMPTY(manager->timers));
4665185a700Sflorian 	manager->done = ISC_TRUE;
4675185a700Sflorian 
4685185a700Sflorian 	/*
4695185a700Sflorian 	 * Clean up.
4705185a700Sflorian 	 */
4715185a700Sflorian 	isc_heap_destroy(&manager->heap);
4725185a700Sflorian 	free(manager);
4735185a700Sflorian 
4745185a700Sflorian 	*managerp = NULL;
4755185a700Sflorian 
4765185a700Sflorian 	timermgr = NULL;
4775185a700Sflorian }
4785185a700Sflorian 
4795185a700Sflorian isc_result_t
4808b553854Sflorian isc_timermgr_nextevent(isc_timermgr_t *manager0, struct timespec *when) {
4818b553854Sflorian 	isc_timermgr_t *manager = (isc_timermgr_t *)manager0;
4825185a700Sflorian 
4835185a700Sflorian 	if (manager == NULL)
4845185a700Sflorian 		manager = timermgr;
4855185a700Sflorian 	if (manager == NULL || manager->nscheduled == 0)
4865185a700Sflorian 		return (ISC_R_NOTFOUND);
4875185a700Sflorian 	*when = manager->due;
4885185a700Sflorian 	return (ISC_R_SUCCESS);
4895185a700Sflorian }
4905185a700Sflorian 
4915185a700Sflorian void
4928b553854Sflorian isc_timermgr_dispatch(isc_timermgr_t *manager0) {
4938b553854Sflorian 	isc_timermgr_t *manager = (isc_timermgr_t *)manager0;
4947238a213Sflorian 	struct timespec now;
4955185a700Sflorian 
4965185a700Sflorian 	if (manager == NULL)
4975185a700Sflorian 		manager = timermgr;
4985185a700Sflorian 	if (manager == NULL)
4995185a700Sflorian 		return;
500b53d8310Sflorian 	clock_gettime(CLOCK_MONOTONIC, &now);
5015185a700Sflorian 	dispatch(manager, &now);
5025185a700Sflorian }
5035185a700Sflorian 
504