/* 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();
	}
	
}
Beispiel #2
0
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;
}
Beispiel #3
0
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();
	}

}