timer.c revision f191e3b4e87f7acb6f6b6536fa18b859265eff5f
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * We use macros instead of calling the routines directly because
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * the capital letters make the locking stand out.
0c310d16b05ee94743d33f6920907edee6084fc8Michael Graff * We INSIST that they succeed since there's no way for us to continue
0c310d16b05ee94743d33f6920907edee6084fc8Michael Graff * if they fail.
ebfcb6cf66283096ebda1503b6cc042ce86b6bedBrian Wellington INSIST(isc_mutex_lock((lp)) == ISC_R_SUCCESS);
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence INSIST(isc_mutex_unlock((lp)) == ISC_R_SUCCESS);
25a66b4e41e2b0a2af4840749bac80ae78c678bfMark Andrews INSIST(isc_condition_broadcast((cvp)) == ISC_R_SUCCESS);
21f1794606dce19928cf455029e173321f166380Mark Andrews INSIST(isc_condition_signal((cvp)) == ISC_R_SUCCESS);
0c310d16b05ee94743d33f6920907edee6084fc8Michael Graff INSIST(isc_condition_wait((cvp), (lp)) == ISC_R_SUCCESS);
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence#define XTRACEID(s, t) printf("%s %p\n", (s), (t))
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews#define XTRACETIME(s, d) printf("%s %lu.%09lu\n", (s), \
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews#define XTRACETIMER(s, t, d) printf("%s %p %lu.%09lu\n", (s), (t), \
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews#define XTRACETIMER(s, t, d)
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews#endif /* ISC_TIMER_TRACE */
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews /* Not locked. */
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews unsigned int magic;
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews /* Locked by timer lock. */
deaaf94332abbfdb3aff53675546acfed16e5eb6Mark Andrews /* Locked by manager lock. */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence unsigned int index;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence#define TIMER_MANAGER_MAGIC 0x54494D4DU /* TIMM. */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence /* Not locked. */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence unsigned int magic;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence /* Locked by manager lock. */
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafssonschedule(isc_timer_t timer, isc_time_t now, isc_boolean_t signal_ok) {
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson * Note: the caller must ensure locking.
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson * Compute the new due time.
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence else if (isc_time_compare(&timer->idle, &timer->expires) < 0)
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * Schedule the timer.
330705066b03f6ce0bc08a4bbfc5d2418038c68dBrian Wellington * Already scheduled.
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_heap_increased(manager->heap, timer->index);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_heap_decreased(manager->heap, timer->index);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence /* Nothing to do. */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence result = isc_heap_insert(manager->heap, timer);
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 Lawrencestatic inline void
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * The caller must ensure locking.
b6a0341bcb113e93bd0bc41a9f9a1fc117444da6Mark Andrews * The caller must ensure locking.
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews isc_task_purge(timer->task, timer, ISC_TASKEVENT_ANYEVENT);
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews isc_mem_put(manager->mctx, timer, sizeof *timer);
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrewsisc_timer_create(isc_timermgr_t manager, isc_timertype_t type,
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews isc_task_t task, isc_taskaction_t action, void *arg,
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'.
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews * Get current time.
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews "isc_time_get() failed: %s",
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington timer = isc_mem_get(manager->mctx, sizeof *timer);
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington if (type == isc_timertype_once && !ZERO(*interval))
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington isc_time_add(&now, interval, &timer->idle);
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews if (isc_mutex_init(&timer->lock) != ISC_R_SUCCESS) {
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews isc_mem_put(manager->mctx, timer, sizeof *timer);
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews "isc_mutex_init() failed");
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.
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)
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.
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson REQUIRE(!(ZERO(*expires) && ZERO(*interval)));
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * Get current time.
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson "isc_time_get() failed: %s",
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson isc_task_purge(timer->task, timer, ISC_TASKEVENT_ANYEVENT);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson if (type == isc_timertype_once && !ZERO(*interval))
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson isc_time_add(&now, interval, &timer->idle);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson result = schedule(timer, &now, ISC_TRUE);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * Set the last-touched time of 'timer' to the current time.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews "isc_time_get() failed: %s",
f1cae4bcb7ee3060d893f5ab3ba55c1820bf3e4aBrian Wellington isc_time_add(&now, &timer->interval, &timer->idle);
6c29053a20f7614167bafa4388c666644a095349Andreas Gustafssonisc_timer_attach(isc_timer_t timer, isc_timer_t *timerp) {
5d2026ea7b5ae43bbd69d98b747f75ba3290bef1Mark Andrews * Attach *timerp to timer.
389c749a5ee18f1c0d6278ae49f2aae5d5f0d2dcMark Andrews * Detach *timerp from its timer.
29c818c7d40fc8898b062903ec703851328a4deaMark Andrewsdispatch(isc_timermgr_t manager, isc_time_t now) {
29c818c7d40fc8898b062903ec703851328a4deaMark Andrews isc_boolean_t done = ISC_FALSE, post_event, need_schedule;
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews * Idle timer has been touched; reschedule.
f1cae4bcb7ee3060d893f5ab3ba55c1820bf3e4aBrian Wellington "couldn't allocate event");
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews "couldn't schedule timer: %s",
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsstatic void *
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews result = WAITUNTIL(&manager->wakeup, &manager->lock,
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graffisc_timermgr_create(isc_memctx_t mctx, isc_timermgr_t *managerp) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * Create a timer manager.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews REQUIRE(managerp != NULL && *managerp == NULL);
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews result = isc_heap_create(mctx, sooner, set_index, 0, &manager->heap);
19d365e4448f1782611280b020987988b7ac3210Mark Andrews if (isc_mutex_init(&manager->lock) != ISC_R_SUCCESS) {
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence "isc_mutex_init() failed");
f0a5bb8f86631ce638cb2b6c65bbb9bcf9b0cdc0Bob Halley if (isc_condition_init(&manager->wakeup) != ISC_R_SUCCESS) {
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews "isc_condition_init() failed");
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews if (isc_thread_create(run, manager, &manager->thread) !=
7e4cda9965e2edf2ec43c57967eec8eff7061ab0Andreas Gustafsson isc_mem_put(mctx, manager, sizeof *manager);
7e4cda9965e2edf2ec43c57967eec8eff7061ab0Andreas Gustafsson "isc_thread_create() failed");
942d1a339b1fe617f7d17d66cb5fccce798d15aeBrian Wellingtonisc_timermgr_destroy(isc_timermgr_t *managerp) {
ebfcb6cf66283096ebda1503b6cc042ce86b6bedBrian Wellington * Destroy a timer manager.
5eb91bd90e3ad3426e5e3213031556a737cf3809Mark Andrews * Wait for thread to exit.
f16495732753175e4a9fc144323a12fdcc29b561Brian Wellington if (isc_thread_join(manager->thread) != ISC_R_SUCCESS)
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington "isc_thread_join() failed");
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington (void)isc_condition_destroy(&manager->wakeup);