/* slow timer main function, never exists * This function is intended to be executed in a special separated process * (the "slow" timer) which will run the timer handlers of all the registered * timers not marked as "fast". The ideea is to execute the fast timers in the * "main" timer process, as accurate as possible and defer the execution of the * timers marked as "slow" to the "slow" timer. * Implementation details: * - it waits for a signal and then wakes up and processes * all the lists in slow_timer_lists from [s_idx, t_idx). It will * -it increments *s_idx (at the end it will be == *t_idx) * -all list operations are protected by the "slow" timer lock */ void slow_timer_main() { int n; ticks_t ret; struct timer_ln* tl; unsigned short i; in_slow_timer=1; /* mark this process as the slow timer */ while(1){ #ifdef USE_SIGWAIT n=sigwait(&slow_timer_sset, 0); #else n=sigwaitinfo(&slow_timer_sset, 0); #endif if (n==-1){ if (errno==EINTR) continue; /* some other signal, ignore it */ LOG(L_ERR, "ERROR: slow_timer_main: sigwaitinfo failed: %s [%d]\n", strerror(errno), errno); sleep(1); /* try to continue */ } LOCK_SLOW_TIMER_LIST(); while(*s_idx!=*t_idx){ i= *s_idx%SLOW_LISTS_NO; while(slow_timer_lists[i].next!= (struct timer_ln*)&slow_timer_lists[i]){ tl=slow_timer_lists[i].next; _timer_rm_list(tl); tl->next=tl->prev=0; #ifdef TIMER_DEBUG tl->expires_no++; #endif SET_RUNNING_SLOW(tl); UNLOCK_SLOW_TIMER_LIST(); ret=tl->f(*ticks, tl, tl->data); if (ret==0){ /* one shot */ UNSET_RUNNING_SLOW(); LOCK_SLOW_TIMER_LIST(); }else{ /* not one shot, re-add it */ LOCK_TIMER_LIST(); /* add it to the "main" list */ RESET_SLOW_LIST(tl); if (ret!=(ticks_t)-1) /* != periodic */ tl->initial_timeout=ret; _timer_add(*ticks, tl); UNLOCK_TIMER_LIST(); LOCK_SLOW_TIMER_LIST(); UNSET_RUNNING_SLOW(); } } (*s_idx)++; } UNLOCK_SLOW_TIMER_LIST(); } }
/* marks a timer as "to be deleted when the handler ends", usefull when * the timer handler knows it won't prolong the timer anymore (it will * return 0) and will do some time consuming work. Calling this function * will cause simultaneous timer_dels to return immediately (they won't * wait anymore for the timer handle to finish). It will also allow * self-deleting from the timer handle without bug reports. * WARNING: - if you rely on timer_del to know when the timer handle execution * finishes (e.g. to free resources used in the timer handle), don't * use this function. * - this function can be called only from a timer handle (in timer * context), all other calls will have no effect and will log a * bug message */ void timer_allow_del(void) { if (IS_IN_TIMER() ){ UNSET_RUNNING(); }else #ifdef USE_SLOW_TIMER if (IS_IN_TIMER_SLOW()){ UNSET_RUNNING_SLOW(); }else #endif LM_CRIT("timer_allow_del called outside a timer handle\n"); }
void slow_timer_main() { int n; ticks_t ret; struct timer_ln* tl; unsigned short i; #ifdef USE_SIGWAIT int sig; #endif in_slow_timer=1; /* mark this process as the slow timer */ while(1){ #ifdef USE_SIGWAIT n=sigwait(&slow_timer_sset, &sig); #else n=sigwaitinfo(&slow_timer_sset, 0); #endif if (n==-1){ if (errno==EINTR) continue; /* some other signal, ignore it */ LM_ERR("sigwaitinfo failed: %s [%d]\n", strerror(errno), errno); sleep(1); /* try to continue */ } #ifdef USE_SIGWAIT if (sig!=SLOW_TIMER_SIG){ #ifdef __OS_darwin /* on darwin sigwait is buggy: it will cause extreme slow down * on signal delivery for the signals it doesn't wait on * (on darwin 8.8.0, g4 1.5Ghz I've measured a 36s delay!). * To work arround this bug, we sigwait() on all the signals we * are interested in ser and manually call the master signal handler * if the signal!= slow timer signal -- andrei */ sig_usr(sig); #endif continue; } #endif /* update the local cfg if needed */ cfg_update(); LOCK_SLOW_TIMER_LIST(); while(*s_idx!=*t_idx){ i= *s_idx%SLOW_LISTS_NO; while(slow_timer_lists[i].next!= (struct timer_ln*)&slow_timer_lists[i]){ tl=slow_timer_lists[i].next; _timer_rm_list(tl); tl->next=tl->prev=0; #ifdef TIMER_DEBUG tl->expires_no++; #endif SET_RUNNING_SLOW(tl); UNLOCK_SLOW_TIMER_LIST(); ret=tl->f(*ticks, tl, tl->data); /* reset the configuration group handles */ cfg_reset_all(); if (ret==0){ /* one shot */ UNSET_RUNNING_SLOW(); LOCK_SLOW_TIMER_LIST(); }else{ /* not one shot, re-add it */ LOCK_TIMER_LIST(); /* add it to the "main" list */ RESET_SLOW_LIST(tl); if (ret!=(ticks_t)-1) /* != periodic */ tl->initial_timeout=ret; _timer_add(*ticks, tl); UNLOCK_TIMER_LIST(); LOCK_SLOW_TIMER_LIST(); UNSET_RUNNING_SLOW(); } } (*s_idx)++; } UNLOCK_SLOW_TIMER_LIST(); } }