mirror of https://github.com/sipwise/rtpengine.git
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.
91 lines
2.4 KiB
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);
|
|
}
|