timer.c revision c403d3f7d6cb17406e9be03a330ed5cf91619abc
/*
* Copyright (C) 1998, 1999, 2000 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
#include <config.h>
#include <stddef.h>
#include <stdlib.h>
#include <isc/condition.h>
#ifdef ISC_TIMER_TRACE
(d).seconds, (d).nanoseconds)
(d).seconds, (d).nanoseconds)
#else
#define XTRACE(s)
#define XTRACEID(s, t)
#define XTRACETIME(s, d)
#define XTRACETIMER(s, t, d)
#endif /* ISC_TIMER_TRACE */
#define VALID_TIMER(t) ((t) != NULL && \
(t)->magic == TIMER_MAGIC)
struct isc_timer {
/* Not locked. */
unsigned int magic;
/* Locked by timer lock. */
unsigned int references;
/* Locked by manager lock. */
isc_task_t * task;
void * arg;
unsigned int index;
};
#define VALID_MANAGER(m) ((m) != NULL && \
(m)->magic == TIMER_MANAGER_MAGIC)
struct isc_timermgr {
/* Not locked. */
unsigned int magic;
/* Locked by manager lock. */
unsigned int nscheduled;
isc_heap_t * heap;
};
static inline isc_result_t
int cmp;
/*
* Note: the caller must ensure locking.
*/
/*
* Compute the new due time.
*/
else {
else
}
/*
* Schedule the timer.
*/
/*
* Already scheduled.
*/
switch (cmp) {
case -1:
break;
case 1:
break;
case 0:
/* Nothing to do. */
break;
}
} else {
if (result != ISC_R_SUCCESS) {
return (ISC_R_NOMEMORY);
}
manager->nscheduled++;
}
/*
* If this timer is at the head of the queue, we wake up the run
* thread. We do this, because we likely have set a more recent
* due time than the one the run thread is sleeping on, and we don't
* want it to oversleep.
*/
XTRACE("signal (schedule)");
}
return (ISC_R_SUCCESS);
}
static inline void
/*
* The caller must ensure locking.
*/
manager->nscheduled--;
if (need_wakeup) {
XTRACE("signal (deschedule)");
}
}
}
static void
/*
* The caller must ensure it is safe to destroy the timer.
*/
NULL);
}
{
/*
* Create a new 'type' timer managed by 'manager'. The timers
* parameters are specified by 'expires' and 'interval'. Events
* will be posted to 'task' and when dispatched 'action' will be
* called with 'arg' as the arg value. The new timer is returned
* in 'timerp'.
*/
/*
* Get current time.
*/
if (type != isc_timertype_inactive) {
if (result != ISC_R_SUCCESS) {
"isc_time_now() failed: %s",
return (ISC_R_UNEXPECTED);
}
} else {
/*
* We don't have to do this, but it keeps the compiler from
* complaining about "now" possibly being used without being
* set, even though it will never actually happen.
*/
}
return (ISC_R_NOMEMORY);
else
"isc_mutex_init() failed");
return (ISC_R_UNEXPECTED);
}
/*
* Note we don't have to lock the timer like we normally would because
* there are no external references to it yet.
*/
if (type != isc_timertype_inactive)
else
if (result == ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS) {
return (result);
}
return (ISC_R_SUCCESS);
}
{
/*
* Change the timer's type, expires, and interval values to the given
* values. If 'purge' is ISC_TRUE, any pending events from this timer
* are purged from its task's event queue.
*/
/*
* Get current time.
*/
if (type != isc_timertype_inactive) {
if (result != ISC_R_SUCCESS) {
"isc_time_now() failed: %s",
return (ISC_R_UNEXPECTED);
}
} else {
/*
* We don't have to do this, but it keeps the compiler from
* complaining about "now" possibly being used without being
* set, even though it will never actually happen.
*/
}
if (purge)
NULL);
else
if (type == isc_timertype_inactive) {
} else
return (result);
}
/*
* Set the last-touched time of 'timer' to the current time.
*/
/*
* We'd like to
*
* REQUIRE(timer->type == isc_timertype_once);
*
* but we cannot without locking the manager lock too, which we
* don't want to do.
*/
if (result != ISC_R_SUCCESS) {
"isc_time_now() failed: %s",
return (ISC_R_UNEXPECTED);
}
return (ISC_R_SUCCESS);
}
void
/*
* Attach *timerp to timer.
*/
timer->references++;
}
void
/*
* Detach *timerp from its timer.
*/
timer->references--;
if (timer->references == 0)
if (free_timer)
}
static void
isc_eventtype_t type = 0;
/*
* The caller must be holding the manager lock.
*/
} else {
/*
* Idle timer has been touched; reschedule.
*/
}
if (post_event) {
/*
* XXX We could preallocate this event.
*/
type,
sizeof *event);
else
"couldn't allocate event");
}
manager->nscheduled--;
if (need_schedule) {
if (result != ISC_R_SUCCESS)
"couldn't schedule timer: %s",
result);
}
} else {
}
}
}
static isc_threadresult_t
#ifdef _WIN32
#endif
if (manager->nscheduled > 0) {
result == ISC_R_TIMEDOUT);
} else {
XTRACE("wait");
}
XTRACE("wakeup");
}
return ((isc_threadresult_t)0);
}
static isc_boolean_t
return (ISC_TRUE);
return (ISC_FALSE);
}
static void
}
/*
* Create a timer manager.
*/
return (ISC_R_NOMEMORY);
manager->nscheduled = 0;
if (result != ISC_R_SUCCESS) {
return (ISC_R_NOMEMORY);
}
"isc_mutex_init() failed");
return (ISC_R_UNEXPECTED);
}
"isc_condition_init() failed");
return (ISC_R_UNEXPECTED);
}
"isc_thread_create() failed");
return (ISC_R_UNEXPECTED);
}
return (ISC_R_SUCCESS);
}
void
/*
* Destroy a timer manager.
*/
XTRACE("signal (destroy)");
/*
* Wait for thread to exit.
*/
"isc_thread_join() failed");
/*
* Clean up.
*/
}