timer.c revision f191e3b4e87f7acb6f6b6536fa18b859265eff5f
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
a7038d1a0513c8e804937ebc95fc9cb3a46c04f5Mark Andrews#include "attribute.h"
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews#include <stddef.h>
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews#include <stdlib.h>
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence#include <isc/assertions.h>
15a44745412679c30a6d022733925af70a38b715David Lawrence#include <isc/unexpect.h>
15a44745412679c30a6d022733925af70a38b715David Lawrence#include <isc/thread.h>
15a44745412679c30a6d022733925af70a38b715David Lawrence#include <isc/mutex.h>
15a44745412679c30a6d022733925af70a38b715David Lawrence#include <isc/condition.h>
15a44745412679c30a6d022733925af70a38b715David Lawrence#include <isc/heap.h>
15a44745412679c30a6d022733925af70a38b715David Lawrence#include <isc/timer.h>
15a44745412679c30a6d022733925af70a38b715David Lawrence
15a44745412679c30a6d022733925af70a38b715David Lawrence/*
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * We use macros instead of calling the routines directly because
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * the capital letters make the locking stand out.
cc083bb7031c04d57cbad41b2f5a796a4fd1865cMark Andrews *
0c310d16b05ee94743d33f6920907edee6084fc8Michael Graff * We INSIST that they succeed since there's no way for us to continue
0c310d16b05ee94743d33f6920907edee6084fc8Michael Graff * if they fail.
de153390f5a1f6d4fa86af91d4cae772d9846ca0Mark Andrews */
0c310d16b05ee94743d33f6920907edee6084fc8Michael Graff
822f6cdabb1edd44472c7a758b5cae71376fa9beBrian Wellington#define LOCK(lp) \
ebfcb6cf66283096ebda1503b6cc042ce86b6bedBrian Wellington INSIST(isc_mutex_lock((lp)) == ISC_R_SUCCESS);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews#define UNLOCK(lp) \
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence INSIST(isc_mutex_unlock((lp)) == ISC_R_SUCCESS);
242bba8991b030b7764f0bdca3922d75c34ea51eAndreas Gustafsson#define BROADCAST(cvp) \
25a66b4e41e2b0a2af4840749bac80ae78c678bfMark Andrews INSIST(isc_condition_broadcast((cvp)) == ISC_R_SUCCESS);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence#define SIGNAL(cvp) \
21f1794606dce19928cf455029e173321f166380Mark Andrews INSIST(isc_condition_signal((cvp)) == ISC_R_SUCCESS);
973a19342597823f111fce6a8cd5adfd0e2e7c0dMark Andrews#define WAIT(cvp, lp) \
0c310d16b05ee94743d33f6920907edee6084fc8Michael Graff INSIST(isc_condition_wait((cvp), (lp)) == ISC_R_SUCCESS);
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence#define WAITUNTIL(cvp, lp, tp) \
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence isc_condition_waituntil((cvp), (lp), (tp))
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence#define ZERO(t) ((t).seconds == 0 && \
21825a8d005ccc2dfaf12889bf9eef3413555277Brian Wellington (t).nanoseconds == 0)
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews#ifdef ISC_TIMER_TRACE
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews#define XTRACE(s) printf("%s\n", (s))
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence#define XTRACEID(s, t) printf("%s %p\n", (s), (t))
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews#define XTRACETIME(s, d) printf("%s %lu.%09lu\n", (s), \
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence (d).seconds, (d).nanoseconds)
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews#define XTRACETIMER(s, t, d) printf("%s %p %lu.%09lu\n", (s), (t), \
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson (d).seconds, (d).nanoseconds)
5fc7ba3e1ac5d72239e9971e0f469dd5796738f9Andreas Gustafsson#else
5fc7ba3e1ac5d72239e9971e0f469dd5796738f9Andreas Gustafsson#define XTRACE(s)
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews#define XTRACEID(s, t)
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews#define XTRACETIME(s, d)
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews#define XTRACETIMER(s, t, d)
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews#endif /* ISC_TIMER_TRACE */
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews#define TIMER_MAGIC 0x54494D52U /* TIMR. */
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews#define VALID_TIMER(t) ((t) != NULL && \
c46f10e4a1702191b003cf8f8fc5059c15d29c48Mark Andrews (t)->magic == TIMER_MAGIC)
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrewsstruct isc_timer {
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews /* Not locked. */
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews unsigned int magic;
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews isc_timermgr_t manager;
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews isc_mutex_t lock;
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews /* Locked by timer lock. */
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews unsigned int references;
eb6bd543c7d072efdca509eb17f8f301c1467b53Mark Andrews struct isc_time idle;
deaaf94332abbfdb3aff53675546acfed16e5eb6Mark Andrews /* Locked by manager lock. */
c46f10e4a1702191b003cf8f8fc5059c15d29c48Mark Andrews isc_timertype_t type;
c46f10e4a1702191b003cf8f8fc5059c15d29c48Mark Andrews struct isc_time expires;
0b056755b2f423ba5f6adac8f7851d78f7d11437David Lawrence struct isc_time interval;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence isc_task_t task;
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews isc_taskaction_t action;
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews void * arg;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence unsigned int index;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence struct isc_time due;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence LINK(struct isc_timer) link;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence};
0b056755b2f423ba5f6adac8f7851d78f7d11437David Lawrence
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence#define TIMER_MANAGER_MAGIC 0x54494D4DU /* TIMM. */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence#define VALID_MANAGER(m) ((m) != NULL && \
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence (m)->magic == TIMER_MANAGER_MAGIC)
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrencestruct isc_timermgr {
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence /* Not locked. */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence unsigned int magic;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence isc_memctx_t mctx;
0b056755b2f423ba5f6adac8f7851d78f7d11437David Lawrence isc_mutex_t lock;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence /* Locked by manager lock. */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence isc_boolean_t done;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence LIST(struct isc_timer) timers;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence unsigned int nscheduled;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence struct isc_time due;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence isc_condition_t wakeup;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence isc_thread_t thread;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence isc_heap_t heap;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence};
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrencestatic inline isc_result
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafssonschedule(isc_timer_t timer, isc_time_t now, isc_boolean_t signal_ok) {
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence isc_result result;
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson isc_timermgr_t manager;
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson struct isc_time due;
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson int cmp;
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson /*
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson * Note: the caller must ensure locking.
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson /*
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson * Compute the new due time.
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence if (timer->type == isc_timertype_ticker)
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_time_add(now, &timer->interval, &due);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence else {
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence if (ZERO(timer->idle))
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence due = timer->expires;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence else if (ZERO(timer->expires))
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence due = timer->idle;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence else if (isc_time_compare(&timer->idle, &timer->expires) < 0)
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence due = timer->idle;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence else
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence due = timer->expires;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence }
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence /*
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * Schedule the timer.
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence manager = timer->manager;
330705066b03f6ce0bc08a4bbfc5d2418038c68dBrian Wellington if (timer->index > 0) {
330705066b03f6ce0bc08a4bbfc5d2418038c68dBrian Wellington /*
330705066b03f6ce0bc08a4bbfc5d2418038c68dBrian Wellington * Already scheduled.
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence cmp = isc_time_compare(&due, &timer->due);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence timer->due = due;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence switch (cmp) {
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence case -1:
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_heap_increased(manager->heap, timer->index);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence break;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence case 1:
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_heap_decreased(manager->heap, timer->index);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence break;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence case 0:
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence /* Nothing to do. */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence break;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence }
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence } else {
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence timer->due = due;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence result = isc_heap_insert(manager->heap, timer);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence if (result != ISC_R_SUCCESS) {
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence INSIST(result == ISC_R_NOMEMORY);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence return (ISC_R_NOMEMORY);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence }
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence manager->nscheduled++;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence }
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence XTRACETIMER("schedule", timer, due);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence /*
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * If this timer is at the head of the queue, we wake up the run
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * thread. We do this, because we likely have set a more recent
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * due time than the one the run thread is sleeping on, and we don't
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * want it to oversleep.
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence if (timer->index == 1 && signal_ok) {
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence XTRACE("signal (schedule)");
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence SIGNAL(&manager->wakeup);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence }
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence return (ISC_R_SUCCESS);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence}
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencestatic inline void
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencedeschedule(isc_timer_t timer) {
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_boolean_t need_wakeup = ISC_FALSE;
76c8294c81fb48b1da6e1fc5b83322a4cedb8e58Andreas Gustafsson isc_timermgr_t manager;
76c8294c81fb48b1da6e1fc5b83322a4cedb8e58Andreas Gustafsson
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence /*
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * The caller must ensure locking.
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence manager = timer->manager;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence if (timer->index > 0) {
fd4810861c0c0ccb9aebde94e9d289442b2630dbMark Andrews if (timer->index == 1)
fd4810861c0c0ccb9aebde94e9d289442b2630dbMark Andrews need_wakeup = ISC_TRUE;
fd4810861c0c0ccb9aebde94e9d289442b2630dbMark Andrews isc_heap_delete(manager->heap, timer->index);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence timer->index = 0;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence INSIST(manager->nscheduled > 0);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence manager->nscheduled--;
7ab0e69f61e61e81d489c95c7ebd981e74e7ef16Andreas Gustafsson if (need_wakeup) {
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews XTRACE("signal (deschedule)");
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews SIGNAL(&manager->wakeup);
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews }
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews }
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews}
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrewsstatic void
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrewsdestroy(isc_timer_t timer) {
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews isc_timermgr_t manager = timer->manager;
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews
23cb957a81a51a9656917ea98d0ae56b7abdcaccMark Andrews /*
b6a0341bcb113e93bd0bc41a9f9a1fc117444da6Mark Andrews * The caller must ensure locking.
b6a0341bcb113e93bd0bc41a9f9a1fc117444da6Mark Andrews */
aa05bbdef7f7827dde158dcc913f4dade84c8511Brian Wellington
23cb957a81a51a9656917ea98d0ae56b7abdcaccMark Andrews LOCK(&manager->lock);
23cb957a81a51a9656917ea98d0ae56b7abdcaccMark Andrews
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews isc_task_purge(timer->task, timer, ISC_TASKEVENT_ANYEVENT);
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews deschedule(timer);
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews UNLINK(manager->timers, timer, link);
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews UNLOCK(&manager->lock);
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews isc_task_detach(&timer->task);
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews (void)isc_mutex_destroy(&timer->lock);
78838d3e0cd62423c23de5503910e01884d2104bBrian Wellington timer->magic = 0;
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews isc_mem_put(manager->mctx, timer, sizeof *timer);
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews}
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrewsisc_result
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrewsisc_timer_create(isc_timermgr_t manager, isc_timertype_t type,
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews isc_time_t expires, isc_time_t interval,
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews isc_task_t task, isc_taskaction_t action, void *arg,
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews isc_timer_t *timerp)
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews{
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews isc_timer_t timer;
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews isc_result result;
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews struct isc_time now;
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews
f6407f9a0b890bebbfd5f738d9c4aef3d3315fe9Michael Graff /*
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews * Create a new 'type' timer managed by 'manager'. The timers
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews * parameters are specified by 'expires' and 'interval'. Events
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews * will be posted to 'task' and when dispatched 'action' will be
ffe74cc719aa0f10c38fbc1f2f3ea7db0960cb8fMark Andrews * called with 'arg' as the arg value. The new timer is returned
ffe74cc719aa0f10c38fbc1f2f3ea7db0960cb8fMark Andrews * in 'timerp'.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews REQUIRE(VALID_MANAGER(manager));
bed8e84810a80dad3d37870be927d1dfd015f480Mark Andrews REQUIRE(task != NULL);
bed8e84810a80dad3d37870be927d1dfd015f480Mark Andrews REQUIRE(action != NULL);
bed8e84810a80dad3d37870be927d1dfd015f480Mark Andrews REQUIRE(!(ZERO(*expires) && ZERO(*interval)));
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews REQUIRE(timerp != NULL && *timerp == NULL);
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews /*
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews * Get current time.
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews */
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews result = isc_time_get(&now);
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews if (result != ISC_R_SUCCESS) {
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews UNEXPECTED_ERROR(__FILE__, __LINE__,
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews "isc_time_get() failed: %s",
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews isc_result_totext(result));
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews return (ISC_R_UNEXPECTED);
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews }
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington timer = isc_mem_get(manager->mctx, sizeof *timer);
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington if (timer == NULL)
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews return (ISC_R_NOMEMORY);
613991eef6bb79b9703382aff26cddd0281da915Bob Halley
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews timer->magic = TIMER_MAGIC;
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews timer->manager = manager;
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington timer->references = 1;
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington if (type == isc_timertype_once && !ZERO(*interval))
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington isc_time_add(&now, interval, &timer->idle);
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington else {
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington timer->idle.seconds = 0;
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington timer->idle.nanoseconds = 0;
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington }
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington timer->type = type;
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington timer->expires = *expires;
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington timer->interval = *interval;
87ecd67dae468cf5c9bae213c6fa321449b2ebc2Andreas Gustafsson timer->task = NULL;
87ecd67dae468cf5c9bae213c6fa321449b2ebc2Andreas Gustafsson isc_task_attach(task, &timer->task);
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews timer->action = action;
87ecd67dae468cf5c9bae213c6fa321449b2ebc2Andreas Gustafsson timer->arg = arg;
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews timer->index = 0;
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews if (isc_mutex_init(&timer->lock) != ISC_R_SUCCESS) {
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews isc_mem_put(manager->mctx, timer, sizeof *timer);
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews UNEXPECTED_ERROR(__FILE__, __LINE__,
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews "isc_mutex_init() failed");
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews return (ISC_R_UNEXPECTED);
36e37042c6c9252cdf6eb99bd71ccb6e6c43ba6dBrian Wellington }
bcd7fdf06ca76eb2f6eb157f56b612c503e062a7Mark Andrews
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews LOCK(&manager->lock);
21825a8d005ccc2dfaf12889bf9eef3413555277Brian Wellington
d9af67ef70db20f94a954cca237b3fdb30ac2bc7Brian Wellington /*
21825a8d005ccc2dfaf12889bf9eef3413555277Brian Wellington * Note we don't have to lock the timer like we normally would because
21825a8d005ccc2dfaf12889bf9eef3413555277Brian Wellington * there are no external references to it yet.
21825a8d005ccc2dfaf12889bf9eef3413555277Brian Wellington */
21825a8d005ccc2dfaf12889bf9eef3413555277Brian Wellington
21825a8d005ccc2dfaf12889bf9eef3413555277Brian Wellington APPEND(manager->timers, timer, link);
21825a8d005ccc2dfaf12889bf9eef3413555277Brian Wellington result = schedule(timer, &now, ISC_TRUE);
21825a8d005ccc2dfaf12889bf9eef3413555277Brian Wellington
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews UNLOCK(&manager->lock);
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson if (result == ISC_R_SUCCESS)
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson *timerp = timer;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson return (result);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson}
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssonisc_result
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssonisc_timer_reset(isc_timer_t timer, isc_timertype_t type,
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson isc_time_t expires, isc_time_t interval, isc_boolean_t purge)
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson{
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews struct isc_time now;
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff isc_timermgr_t manager;
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews isc_result result;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence /*
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff * Change the timer's type, expires, and interval values to the given
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff * values. If 'purge' is ISC_TRUE, any pending events from this timer
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington * are purged from its task's event queue.
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington */
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff REQUIRE(VALID_TIMER(timer));
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff manager = timer->manager;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson REQUIRE(VALID_MANAGER(manager));
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson REQUIRE(!(ZERO(*expires) && ZERO(*interval)));
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson /*
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * Get current time.
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson */
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson result = isc_time_get(&now);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson if (result != ISC_R_SUCCESS) {
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson UNEXPECTED_ERROR(__FILE__, __LINE__,
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson "isc_time_get() failed: %s",
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson isc_result_totext(result));
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson return (ISC_R_UNEXPECTED);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson }
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson manager = timer->manager;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson LOCK(&manager->lock);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson LOCK(&timer->lock);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson if (purge)
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson isc_task_purge(timer->task, timer, ISC_TASKEVENT_ANYEVENT);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson timer->type = type;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson timer->expires = *expires;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson timer->interval = *interval;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson if (type == isc_timertype_once && !ZERO(*interval))
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson isc_time_add(&now, interval, &timer->idle);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson else {
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson timer->idle.seconds = 0;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson timer->idle.nanoseconds = 0;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson }
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson result = schedule(timer, &now, ISC_TRUE);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson UNLOCK(&timer->lock);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson UNLOCK(&manager->lock);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson return (result);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson}
b0c15bd9792112fb47f6d956e580e4369e92f4e7Mark Andrews
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrenceisc_result
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssonisc_timer_touch(isc_timer_t timer) {
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews isc_result result;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews struct isc_time now;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews /*
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * Set the last-touched time of 'timer' to the current time.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews REQUIRE(VALID_TIMER(timer));
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews LOCK(&timer->lock);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews INSIST(timer->type == isc_timertype_once);
d981ca645597116d227a48bf37cc5edc061c854dBob Halley
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews result = isc_time_get(&now);
e6bd97dded968f82e26b270842b789bff7bca422Mark Andrews if (result != ISC_R_SUCCESS) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews UNEXPECTED_ERROR(__FILE__, __LINE__,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews "isc_time_get() failed: %s",
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_result_totext(result));
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews return (ISC_R_UNEXPECTED);
5d2026ea7b5ae43bbd69d98b747f75ba3290bef1Mark Andrews }
f1cae4bcb7ee3060d893f5ab3ba55c1820bf3e4aBrian Wellington isc_time_add(&now, &timer->interval, &timer->idle);
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews UNLOCK(&timer->lock);
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews
5d2026ea7b5ae43bbd69d98b747f75ba3290bef1Mark Andrews return (ISC_R_SUCCESS);
6c29053a20f7614167bafa4388c666644a095349Andreas Gustafsson}
5d2026ea7b5ae43bbd69d98b747f75ba3290bef1Mark Andrews
5d2026ea7b5ae43bbd69d98b747f75ba3290bef1Mark Andrewsvoid
6c29053a20f7614167bafa4388c666644a095349Andreas Gustafssonisc_timer_attach(isc_timer_t timer, isc_timer_t *timerp) {
6c29053a20f7614167bafa4388c666644a095349Andreas Gustafsson /*
5d2026ea7b5ae43bbd69d98b747f75ba3290bef1Mark Andrews * Attach *timerp to timer.
5f7a9845e900bc491db9feab137895721073631fMark Andrews */
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews REQUIRE(VALID_TIMER(timer));
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews REQUIRE(timerp != NULL && *timerp == NULL);
389c749a5ee18f1c0d6278ae49f2aae5d5f0d2dcMark Andrews
368b37b616234fce3d23099eb180f1dd38e1fb62Mark Andrews LOCK(&timer->lock);
389c749a5ee18f1c0d6278ae49f2aae5d5f0d2dcMark Andrews timer->references++;
cabaeca9ae5b98c80586b91e89cf552e17a75a9bBrian Wellington UNLOCK(&timer->lock);
cabaeca9ae5b98c80586b91e89cf552e17a75a9bBrian Wellington
389c749a5ee18f1c0d6278ae49f2aae5d5f0d2dcMark Andrews *timerp = timer;
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews}
389c749a5ee18f1c0d6278ae49f2aae5d5f0d2dcMark Andrews
389c749a5ee18f1c0d6278ae49f2aae5d5f0d2dcMark Andrewsvoid
389c749a5ee18f1c0d6278ae49f2aae5d5f0d2dcMark Andrewsisc_timer_detach(isc_timer_t *timerp) {
389c749a5ee18f1c0d6278ae49f2aae5d5f0d2dcMark Andrews isc_timer_t timer;
389c749a5ee18f1c0d6278ae49f2aae5d5f0d2dcMark Andrews isc_boolean_t free_timer = ISC_FALSE;
389c749a5ee18f1c0d6278ae49f2aae5d5f0d2dcMark Andrews
389c749a5ee18f1c0d6278ae49f2aae5d5f0d2dcMark Andrews /*
389c749a5ee18f1c0d6278ae49f2aae5d5f0d2dcMark Andrews * Detach *timerp from its timer.
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews */
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews REQUIRE(timerp != NULL);
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews timer = *timerp;
29c818c7d40fc8898b062903ec703851328a4deaMark Andrews REQUIRE(VALID_TIMER(timer));
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews LOCK(&timer->lock);
cabaeca9ae5b98c80586b91e89cf552e17a75a9bBrian Wellington REQUIRE(timer->references > 0);
cabaeca9ae5b98c80586b91e89cf552e17a75a9bBrian Wellington timer->references--;
cabaeca9ae5b98c80586b91e89cf552e17a75a9bBrian Wellington if (timer->references == 0)
f1cae4bcb7ee3060d893f5ab3ba55c1820bf3e4aBrian Wellington free_timer = ISC_TRUE;
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews UNLOCK(&timer->lock);
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews if (free_timer)
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews destroy(timer);
29c818c7d40fc8898b062903ec703851328a4deaMark Andrews
29c818c7d40fc8898b062903ec703851328a4deaMark Andrews *timerp = NULL;
29c818c7d40fc8898b062903ec703851328a4deaMark Andrews}
29c818c7d40fc8898b062903ec703851328a4deaMark Andrews
29c818c7d40fc8898b062903ec703851328a4deaMark Andrewsstatic void
29c818c7d40fc8898b062903ec703851328a4deaMark Andrewsdispatch(isc_timermgr_t manager, isc_time_t now) {
29c818c7d40fc8898b062903ec703851328a4deaMark Andrews isc_boolean_t done = ISC_FALSE, post_event, need_schedule;
29c818c7d40fc8898b062903ec703851328a4deaMark Andrews isc_event_t event;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_eventtype_t type = 0;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_timer_t timer;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_result result;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews while (manager->nscheduled > 0 && !done) {
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence timer = isc_heap_element(manager->heap, 1);
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews if (isc_time_compare(now, &timer->due) >= 0) {
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews if (timer->type == isc_timertype_ticker) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews type = ISC_TIMEREVENT_TICK;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews post_event = ISC_TRUE;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews need_schedule = ISC_TRUE;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews } else if (!ZERO(timer->expires) &&
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_time_compare(now,
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews &timer->expires) >= 0) {
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews type = ISC_TIMEREVENT_LIFE;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews post_event = ISC_TRUE;
d981ca645597116d227a48bf37cc5edc061c854dBob Halley need_schedule = ISC_FALSE;
d981ca645597116d227a48bf37cc5edc061c854dBob Halley } else if (!ZERO(timer->idle) &&
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_time_compare(now,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews &timer->idle) >= 0) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews type = ISC_TIMEREVENT_IDLE;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews post_event = ISC_TRUE;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews need_schedule = ISC_FALSE;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews } else {
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews /*
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews * Idle timer has been touched; reschedule.
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews */
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews XTRACEID("idle reschedule", timer);
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews post_event = ISC_FALSE;
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews need_schedule = ISC_TRUE;
90e303b114e56db5809fdd19805243457fa43cd9Olafur Gudmundsson }
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews if (post_event) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews XTRACEID("posting", timer);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews event = isc_event_allocate(manager->mctx,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews timer,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews type,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews timer->action,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews timer->arg,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews sizeof *event);
d981ca645597116d227a48bf37cc5edc061c854dBob Halley
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews if (event != NULL)
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews isc_task_send(timer->task, &event);
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence else
19d365e4448f1782611280b020987988b7ac3210Mark Andrews UNEXPECTED_ERROR(__FILE__, __LINE__,
f1cae4bcb7ee3060d893f5ab3ba55c1820bf3e4aBrian Wellington "couldn't allocate event");
19d365e4448f1782611280b020987988b7ac3210Mark Andrews }
19d365e4448f1782611280b020987988b7ac3210Mark Andrews
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews timer->index = 0;
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews isc_heap_delete(manager->heap, 1);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews manager->nscheduled--;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
d981ca645597116d227a48bf37cc5edc061c854dBob Halley if (need_schedule) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews result = schedule(timer, now, ISC_FALSE);
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews if (result != ISC_R_SUCCESS)
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews UNEXPECTED_ERROR(__FILE__, __LINE__,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews "couldn't schedule timer: %s",
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews result);
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence }
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews } else {
19d365e4448f1782611280b020987988b7ac3210Mark Andrews manager->due = timer->due;
19d365e4448f1782611280b020987988b7ac3210Mark Andrews done = ISC_TRUE;
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews }
19d365e4448f1782611280b020987988b7ac3210Mark Andrews }
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews}
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsstatic void *
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsrun(void *uap) {
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff isc_timermgr_t manager = uap;
d981ca645597116d227a48bf37cc5edc061c854dBob Halley struct isc_time now;
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews isc_result_t result;
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews LOCK(&manager->lock);
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews while (!manager->done) {
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff INSIST(isc_time_get(&now) == ISC_R_SUCCESS);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews XTRACETIME("running", now);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews dispatch(manager, &now);
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews if (manager->nscheduled > 0) {
19d365e4448f1782611280b020987988b7ac3210Mark Andrews XTRACETIME("waituntil", manager->due);
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews result = WAITUNTIL(&manager->wakeup, &manager->lock,
f1cae4bcb7ee3060d893f5ab3ba55c1820bf3e4aBrian Wellington &manager->due);
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews INSIST(result == ISC_R_SUCCESS ||
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews result == ISC_R_TIMEDOUT);
19d365e4448f1782611280b020987988b7ac3210Mark Andrews } else {
6bebabb376b93e7d12f53a253b197a3fc0e0b001Andreas Gustafsson XTRACE("wait");
6bebabb376b93e7d12f53a253b197a3fc0e0b001Andreas Gustafsson WAIT(&manager->wakeup, &manager->lock);
6bebabb376b93e7d12f53a253b197a3fc0e0b001Andreas Gustafsson }
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews XTRACE("wakeup");
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews }
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews UNLOCK(&manager->lock);
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews return (NULL);
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews}
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsstatic isc_boolean_t
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrewssooner(void *v1, void *v2) {
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews isc_timer_t t1, t2;
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews t1 = v1;
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews t2 = v2;
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews REQUIRE(VALID_TIMER(t1));
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews REQUIRE(VALID_TIMER(t2));
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews if (isc_time_compare(&t1->due, &t2->due) < 0)
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews return (ISC_TRUE);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews return (ISC_FALSE);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence}
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencestatic void
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graffset_index(void *what, unsigned int index) {
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews isc_timer_t timer;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
ad7209ea70d346527ffdcda335153831341d9dcfAndreas Gustafsson timer = what;
7d8cdd869ed2162a5befda7cc1600136110f54d6Mark Andrews REQUIRE(VALID_TIMER(timer));
7d8cdd869ed2162a5befda7cc1600136110f54d6Mark Andrews
7d8cdd869ed2162a5befda7cc1600136110f54d6Mark Andrews timer->index = index;
d981ca645597116d227a48bf37cc5edc061c854dBob Halley}
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsisc_result
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graffisc_timermgr_create(isc_memctx_t mctx, isc_timermgr_t *managerp) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_timermgr_t manager;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_result result;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews /*
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * Create a timer manager.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews */
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews REQUIRE(managerp != NULL && *managerp == NULL);
78838d3e0cd62423c23de5503910e01884d2104bBrian Wellington
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews manager = isc_mem_get(mctx, sizeof *manager);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff if (manager == NULL)
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews return (ISC_R_NOMEMORY);
f0a5bb8f86631ce638cb2b6c65bbb9bcf9b0cdc0Bob Halley
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews manager->magic = TIMER_MANAGER_MAGIC;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews manager->mctx = mctx;
19d365e4448f1782611280b020987988b7ac3210Mark Andrews manager->done = ISC_FALSE;
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews INIT_LIST(manager->timers);
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence manager->nscheduled = 0;
693ddf84daa745a0ea8ca311a8154dfa03eabc43Andreas Gustafsson manager->due.seconds = 0;
693ddf84daa745a0ea8ca311a8154dfa03eabc43Andreas Gustafsson manager->due.nanoseconds = 0;
693ddf84daa745a0ea8ca311a8154dfa03eabc43Andreas Gustafsson manager->heap = NULL;
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews result = isc_heap_create(mctx, sooner, set_index, 0, &manager->heap);
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews if (result != ISC_R_SUCCESS) {
693ddf84daa745a0ea8ca311a8154dfa03eabc43Andreas Gustafsson INSIST(result == ISC_R_NOMEMORY);
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews isc_mem_put(mctx, manager, sizeof *manager);
693ddf84daa745a0ea8ca311a8154dfa03eabc43Andreas Gustafsson return (ISC_R_NOMEMORY);
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews }
19d365e4448f1782611280b020987988b7ac3210Mark Andrews if (isc_mutex_init(&manager->lock) != ISC_R_SUCCESS) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_heap_destroy(&manager->heap);
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence isc_mem_put(mctx, manager, sizeof *manager);
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews UNEXPECTED_ERROR(__FILE__, __LINE__,
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence "isc_mutex_init() failed");
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence return (ISC_R_UNEXPECTED);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff }
f0a5bb8f86631ce638cb2b6c65bbb9bcf9b0cdc0Bob Halley if (isc_condition_init(&manager->wakeup) != ISC_R_SUCCESS) {
f0a5bb8f86631ce638cb2b6c65bbb9bcf9b0cdc0Bob Halley (void)isc_mutex_destroy(&manager->lock);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff isc_heap_destroy(&manager->heap);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_mem_put(mctx, manager, sizeof *manager);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff UNEXPECTED_ERROR(__FILE__, __LINE__,
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews "isc_condition_init() failed");
7c0378745269fe49a05904935afc42b85528f53aDavid Lawrence return (ISC_R_UNEXPECTED);
7c0378745269fe49a05904935afc42b85528f53aDavid Lawrence }
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews if (isc_thread_create(run, manager, &manager->thread) !=
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews ISC_R_SUCCESS) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews (void)isc_condition_destroy(&manager->wakeup);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews (void)isc_mutex_destroy(&manager->lock);
7e4cda9965e2edf2ec43c57967eec8eff7061ab0Andreas Gustafsson isc_heap_destroy(&manager->heap);
7e4cda9965e2edf2ec43c57967eec8eff7061ab0Andreas Gustafsson isc_mem_put(mctx, manager, sizeof *manager);
7e4cda9965e2edf2ec43c57967eec8eff7061ab0Andreas Gustafsson UNEXPECTED_ERROR(__FILE__, __LINE__,
7e4cda9965e2edf2ec43c57967eec8eff7061ab0Andreas Gustafsson "isc_thread_create() failed");
7e4cda9965e2edf2ec43c57967eec8eff7061ab0Andreas Gustafsson return (ISC_R_UNEXPECTED);
3a16668468060842e847ea6556e80e1405d35cd6Brian Wellington }
7e4cda9965e2edf2ec43c57967eec8eff7061ab0Andreas Gustafsson
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington *managerp = manager;
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews
ebfcb6cf66283096ebda1503b6cc042ce86b6bedBrian Wellington return (ISC_R_SUCCESS);
7d8cdd869ed2162a5befda7cc1600136110f54d6Mark Andrews}
ebfcb6cf66283096ebda1503b6cc042ce86b6bedBrian Wellington
ebfcb6cf66283096ebda1503b6cc042ce86b6bedBrian Wellingtonvoid
942d1a339b1fe617f7d17d66cb5fccce798d15aeBrian Wellingtonisc_timermgr_destroy(isc_timermgr_t *managerp) {
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington isc_timermgr_t manager;
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington /*
ebfcb6cf66283096ebda1503b6cc042ce86b6bedBrian Wellington * Destroy a timer manager.
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews */
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews REQUIRE(managerp != NULL);
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews manager = *managerp;
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington REQUIRE(VALID_MANAGER(manager));
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington LOCK(&manager->lock);
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington REQUIRE(EMPTY(manager->timers));
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington manager->done = ISC_TRUE;
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington UNLOCK(&manager->lock);
de5247ae1683ce145662180ee50272d2214a0232Andreas Gustafsson
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington XTRACE("signal (destroy)");
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington SIGNAL(&manager->wakeup);
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington /*
5eb91bd90e3ad3426e5e3213031556a737cf3809Mark Andrews * Wait for thread to exit.
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington */
f16495732753175e4a9fc144323a12fdcc29b561Brian Wellington if (isc_thread_join(manager->thread) != ISC_R_SUCCESS)
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington UNEXPECTED_ERROR(__FILE__, __LINE__,
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington "isc_thread_join() failed");
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington
e086935752b6e2f51ef2985fee21ccfff617b115David Lawrence /*
e086935752b6e2f51ef2985fee21ccfff617b115David Lawrence * Clean up.
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington */
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington (void)isc_condition_destroy(&manager->wakeup);
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington (void)isc_mutex_destroy(&manager->lock);
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington isc_heap_destroy(&manager->heap);
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington manager->magic = 0;
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington isc_mem_put(manager->mctx, manager, sizeof *manager);
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington *managerp = NULL;
7e4cda9965e2edf2ec43c57967eec8eff7061ab0Andreas Gustafsson}
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington