@ -15,6 +15,7 @@ static void timerthread_thread_init(struct timerthread_thread *tt, struct timert
cond_init ( & tt - > cond ) ;
tt - > parent = parent ;
ZERO ( tt - > next_wake ) ;
tt - > obj = NULL ;
}
void timerthread_init ( struct timerthread * tt , unsigned int num , void ( * func ) ( void * ) ) {
@ -35,6 +36,8 @@ static int __tt_put_all(void *k, void *d, void *p) {
static void timerthread_thread_destroy ( struct timerthread_thread * tt ) {
g_tree_foreach ( tt - > tree , __tt_put_all , tt ) ;
g_tree_destroy ( tt - > tree ) ;
if ( tt - > obj )
obj_put ( tt - > obj ) ;
mutex_destroy ( & tt - > lock ) ;
}
@ -56,24 +59,33 @@ static void timerthread_run(void *p) {
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 */
long long sleeptime = 10000000 ;
if ( ! tt_obj )
goto sleep ;
/ / find the first element if we haven ' t determined it yet
struct timerthread_obj * tt_obj = tt - > obj ;
if ( ! tt_obj ) {
tt_obj = g_tree_find_first ( tt - > tree , NULL , NULL ) ;
if ( ! tt_obj )
goto sleep_now ;
/ / immediately steal reference
/ / XXX ideally we would have a tree_steal_first ( ) function
g_tree_remove ( tt - > tree , tt_obj ) ;
}
/ / scheduled to run ? if not , then we remember this object / reference and go to sleep
sleeptime = timeval_diff ( & tt_obj - > next_check , & rtpe_now ) ;
if ( sleeptime > 0 )
if ( sleeptime > 0 ) {
tt - > obj = tt_obj ;
goto sleep ;
}
/ / steal reference
g_tree_remove ( tt - > tree , tt_obj ) ;
/ / pretend we ' re running exactly at the scheduled time
rtpe_now = tt_obj - > next_check ;
ZERO ( tt_obj - > next_check ) ;
tt_obj - > last_run = rtpe_now ;
ZERO ( tt - > next_wake ) ;
tt - > obj = NULL ;
mutex_unlock ( & tt - > lock ) ;
/ / run and release
@ -85,9 +97,10 @@ static void timerthread_run(void *p) {
mutex_lock ( & tt - > lock ) ;
continue ;
sleep : ;
sleep :
/* figure out how long we should sleep */
sleeptime = MIN ( 10000000 , sleeptime ) ; /* 100 ms at the most */
sleeptime = MIN ( 10000000 , sleeptime ) ;
sleep_now : ;
struct timeval tv = rtpe_now ;
timeval_add_usec ( & tv , sleeptime ) ;
tt - > next_wake = tv ;
@ -113,13 +126,23 @@ void timerthread_obj_schedule_abs_nl(struct timerthread_obj *tt_obj, const struc
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 */
if ( ! g_tree_remove ( tt - > tree , tt_obj ) ) {
if ( tt - > obj = = tt_obj )
tt - > obj = NULL ;
else
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 ) ;
/ / need to wake the thread ?
if ( tt - > next_wake . tv_sec & & timeval_cmp ( tv , & tt - > next_wake ) < 0 )
if ( tt - > next_wake . tv_sec & & timeval_cmp ( tv , & tt - > next_wake ) < 0 ) {
/ / make sure we can get picked first : move pre - picked object back into tree
if ( tt - > obj & & tt - > obj ! = tt_obj ) {
g_tree_insert ( tt - > tree , tt - > obj , tt - > obj ) ;
tt - > obj = NULL ;
}
cond_signal ( & tt - > cond ) ;
}
}
void timerthread_obj_deschedule ( struct timerthread_obj * tt_obj ) {
@ -134,6 +157,12 @@ void timerthread_obj_deschedule(struct timerthread_obj *tt_obj) {
if ( ! tt_obj - > next_check . tv_sec )
goto nope ; /* already descheduled */
gboolean ret = g_tree_remove ( tt - > tree , tt_obj ) ;
if ( ! ret ) {
if ( tt - > obj = = tt_obj ) {
tt - > obj = NULL ;
ret = TRUE ;
}
}
ZERO ( tt_obj - > next_check ) ;
if ( ret )
obj_put ( tt_obj ) ;