You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rtpengine/daemon/timerthread.c

91 lines
2.4 KiB

#include "timerthread.h"
#include "aux.h"
static int tt_obj_cmp(const void *a, const void *b) {
const struct timerthread_obj *A = a, *B = b;
return timeval_cmp_ptr(&A->next_check, &B->next_check);
}
void timerthread_init(struct timerthread *tt, void (*func)(void *)) {
tt->tree = g_tree_new(tt_obj_cmp);
mutex_init(&tt->lock);
cond_init(&tt->cond);
tt->func = func;
}
void timerthread_run(void *p) {
struct timerthread *tt = p;
mutex_lock(&tt->lock);
while (!rtpe_shutdown) {
gettimeofday(&rtpe_now, NULL);
/* lock our list and get the first element */
struct timerthread_obj *tt_obj = g_tree_find_first(tt->tree, NULL, NULL);
/* scheduled to run? if not, we just go to sleep, otherwise we remove it from the tree,
* steal the reference and run it */
if (!tt_obj)
goto sleep;
if (timeval_cmp(&rtpe_now, &tt_obj->next_check) < 0)
goto sleep;
// steal reference
g_tree_remove(tt->tree, tt_obj);
ZERO(tt_obj->next_check);
tt_obj->last_run = rtpe_now;
mutex_unlock(&tt->lock);
// run and release
tt->func(tt_obj);
obj_put(tt_obj);
mutex_lock(&tt->lock);
continue;
sleep:;
/* figure out how long we should sleep */
long long sleeptime = tt_obj ? timeval_diff(&tt_obj->next_check, &rtpe_now) : 100000;
sleeptime = MIN(100000, sleeptime); /* 100 ms at the most */
struct timeval tv = rtpe_now;
timeval_add_usec(&tv, sleeptime);
cond_timedwait(&tt->cond, &tt->lock, &tv);
}
mutex_unlock(&tt->lock);
}
void timerthread_obj_schedule_abs_nl(struct timerthread_obj *tt_obj, const struct timeval *tv) {
if (!tt_obj)
return;
ilog(LOG_DEBUG, "scheduling timer object at %llu.%06lu", (unsigned long long) tv->tv_sec,
(unsigned long) tv->tv_usec);
struct timerthread *tt = tt_obj->tt;
if (tt_obj->next_check.tv_sec && timeval_cmp(&tt_obj->next_check, tv) <= 0)
return; /* already scheduled sooner */
if (!g_tree_remove(tt->tree, tt_obj))
obj_hold(tt_obj); /* if it wasn't removed, we make a new reference */
tt_obj->next_check = *tv;
g_tree_insert(tt->tree, tt_obj, tt_obj);
cond_broadcast(&tt->cond);
}
void timerthread_obj_deschedule(struct timerthread_obj *tt_obj) {
if (!tt_obj)
return;
struct timerthread *tt = tt_obj->tt;
mutex_lock(&tt->lock);
if (!tt_obj->next_check.tv_sec)
goto nope; /* already descheduled */
int ret = g_tree_remove(tt->tree, tt_obj);
ZERO(tt_obj->next_check);
if (ret)
obj_put(tt_obj);
nope:
mutex_unlock(&tt->lock);
}