/* 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(); } }
int timer_del_safe(struct timer_ln* tl) #endif { int ret; ret=-1; again: /* quick exit if timer inactive */ if ( !(tl->flags & F_TIMER_ACTIVE)){ #ifdef TIMER_DEBUG LOG(timerlog, "timer_del called on an inactive timer %p (%p, %p)," " flags %x\n", tl, tl->next, tl->prev, tl->flags); LOG(timerlog, "WARN: -timer_del-; called from %s(%s):%d\n", func, file, line); LOG(timerlog, "WARN: -timer_del-: added %d times" ", last from: %s(%s):%d, deleted %d times" ", last from: %s(%s):%d, init %d times, expired %d \n", tl->add_calls, tl->add_func, tl->add_file, tl->add_line, tl->del_calls, tl->del_func, tl->del_file, tl->del_line, tl->init, tl->expires_no); #else /* LM_DBG("called on an inactive timer %p (%p, %p)," " flags %x\n", tl, tl->next, tl->prev, tl->flags); */ #endif return -1; } #ifdef USE_SLOW_TIMER if (IS_ON_SLOW_LIST(tl) && (tl->slow_idx!=*t_idx)){ LOCK_SLOW_TIMER_LIST(); if (!IS_ON_SLOW_LIST(tl) || (tl->slow_idx==*t_idx)){ UNLOCK_SLOW_TIMER_LIST(); goto again; } if (IS_RUNNING_SLOW(tl)){ UNLOCK_SLOW_TIMER_LIST(); if (IS_IN_TIMER_SLOW()){ /* if somebody tries to shoot himself in the foot, * warn him and ignore the delete */ LM_CRIT("timer handle %p (s) tried to delete" " itself\n", tl); #ifdef TIMER_DEBUG LOG(timerlog, "WARN: -timer_del-: called from %s(%s):%d\n", func, file, line); LOG(timerlog, "WARN: -timer_del-: added %d times" ", last from: %s(%s):%d, deleted %d times" ", last from: %s(%s):%d, init %d times, expired %d \n", tl->add_calls, tl->add_func, tl->add_file, tl->add_line, tl->del_calls, tl->del_func, tl->del_file, tl->del_line, tl->init, tl->expires_no); #endif return -2; /* do nothing */ } sched_yield(); /* wait for it to complete */ goto again; } if (tl->next!=0){ _timer_rm_list(tl); /* detach */ tl->next=tl->prev=0; ret=0; #ifdef TIMER_DEBUG tl->del_file=file; tl->del_func=func; tl->del_line=line; tl->flags|=F_TIMER_DELETED; #endif }else{ #ifdef TIMER_DEBUG LOG(timerlog, "timer_del: (s) timer %p (%p, %p) flags %x " "already detached\n", tl, tl->next, tl->prev, tl->flags); LOG(timerlog, "WARN: -timer_del-: @%d tl=%p " "{ %p, %p, %d, %d, %p, %p, %04x, -}\n", get_ticks_raw(), tl, tl->next, tl->prev, tl->expire, tl->initial_timeout, tl->data, tl->f, tl->flags); LOG(timerlog, "WARN: -timer_del-; called from %s(%s):%d\n", func, file, line); LOG(timerlog, "WARN: -timer_del-: added %d times" ", last from: %s(%s):%d, deleted %d times" ", last from: %s(%s):%d, init %d times, expired %d \n", tl->add_calls, tl->add_func, tl->add_file, tl->add_line, tl->del_calls, tl->del_func, tl->del_file, tl->del_line, tl->init, tl->expires_no); #else /* LM_DBG("(s) timer %p (%p, %p) flags %x " "already detached\n", tl, tl->next, tl->prev, tl->flags); */ #endif ret=-1; } UNLOCK_SLOW_TIMER_LIST(); }else{ #endif LOCK_TIMER_LIST(); #ifdef USE_SLOW_TIMER if (IS_ON_SLOW_LIST(tl) && (tl->slow_idx!=*t_idx)){ UNLOCK_TIMER_LIST(); goto again; } #endif if (IS_RUNNING(tl)){ UNLOCK_TIMER_LIST(); if (IS_IN_TIMER()){ /* if somebody tries to shoot himself in the foot, * warn him and ignore the delete */ LM_CRIT("timer handle %p tried to delete" " itself\n", tl); #ifdef TIMER_DEBUG LOG(timerlog, "WARN: -timer_del-: called from %s(%s):%d\n", func, file, line); LOG(timerlog, "WARN: -timer_del-: added %d times" ", last from: %s(%s):%d, deleted %d times" ", last from: %s(%s):%d, init %d times, expired %d \n", tl->add_calls, tl->add_func, tl->add_file, tl->add_line, tl->del_calls, tl->del_func, tl->del_file, tl->del_line, tl->init, tl->expires_no); #endif return -2; /* do nothing */ } sched_yield(); /* wait for it to complete */ goto again; } if ((tl->next!=0)&&(tl->prev!=0)){ _timer_rm_list(tl); /* detach */ tl->next=tl->prev=0; ret=0; #ifdef TIMER_DEBUG tl->del_file=file; tl->del_func=func; tl->del_line=line; tl->flags|=F_TIMER_DELETED; #endif }else{ #ifdef TIMER_DEBUG LOG(timerlog, "timer_del: (f) timer %p (%p, %p) flags %x " "already detached\n", tl, tl->next, tl->prev, tl->flags); LOG(timerlog, "WARN: -timer_del-: @%d tl=%p " "{ %p, %p, %d, %d, %p, %p, %04x, -}\n", get_ticks_raw(), tl, tl->next, tl->prev, tl->expire, tl->initial_timeout, tl->data, tl->f, tl->flags); LOG(timerlog, "WARN: -timer_del-; called from %s(%s):%d\n", func, file, line); LOG(timerlog, "WARN: -timer_del-: added %d times" ", last from: %s(%s):%d, deleted %d times" ", last from: %s(%s):%d, init %d times, expired %d \n", tl->add_calls, tl->add_func, tl->add_file, tl->add_line, tl->del_calls, tl->del_func, tl->del_file, tl->del_line, tl->init, tl->expires_no); #else /* LM_DBG("(f) timer %p (%p, %p) flags %x " "already detached\n", tl, tl->next, tl->prev, tl->flags); */ #endif ret=-1; } UNLOCK_TIMER_LIST(); #ifdef USE_SLOW_TIMER } #endif return ret; }
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(); } }