Example #1
0
/* "main" timer routine
 * WARNING: it should never be called twice for the same *ticks value
 * (it could cause too fast expires for long timers), *ticks must be also
 *  always increasing */
static void timer_handler(void)
{
	ticks_t saved_ticks;
#ifdef USE_SLOW_TIMER
	int run_slow_timer;
	int i;

	run_slow_timer=0;
	i=(slow_idx_t)(*t_idx%SLOW_LISTS_NO);
#endif

	/*LM_DBG("called, ticks=%lu, prev_ticks=%lu\n",
			(unsigned long)*ticks, (unsigned long)prev_ticks);
	*/
	run_timer=0; /* reset run_timer */
	adjust_ticks();
	LOCK_TIMER_LIST();
	do{
		saved_ticks=*ticks; /* protect against time running backwards */
		if (prev_ticks>=saved_ticks){
			LM_CRIT("backwards or still time\n");
			/* try to continue */
			prev_ticks=saved_ticks-1;
			break;
		}
		/* go through all the "missed" ticks, taking a possible overflow
		 * into account */
		for (prev_ticks=prev_ticks+1; prev_ticks!=saved_ticks; prev_ticks++)
			timer_run(prev_ticks);
		timer_run(prev_ticks); /* do it for saved_ticks too */
	}while(saved_ticks!=*ticks); /* in case *ticks changed */
#ifdef USE_SLOW_TIMER
	timer_list_expire(*ticks, &timer_lst->expired, &slow_timer_lists[i],
						*t_idx);
#else
	timer_list_expire(*ticks, &timer_lst->expired);
#endif
	/* WARNING: add_timer(...,0) must go directly to expired list, since
	 * otherwise there is a race between timer running and adding it
	 * (it could expire it H0_ENTRIES ticks later instead of 'now')*/
#ifdef USE_SLOW_TIMER
	if (slow_timer_lists[i].next!=(struct timer_ln*)&slow_timer_lists[i]){
		run_slow_timer=1;
		if ((slow_idx_t)(*t_idx-*s_idx) < (SLOW_LISTS_NO-1U))
			(*t_idx)++;
		else{
			LM_WARN("slow timer too slow: overflow (%d - %d = %d)\n",
					*t_idx, *s_idx, *t_idx-*s_idx);
			/* trying to continue */
		}
	}
#endif
	UNLOCK_TIMER_LIST();
#ifdef USE_SLOW_TIMER
	/* wake up the "slow" timer */
	if (run_slow_timer)
		kill(slow_timer_pid, SLOW_TIMER_SIG);
#endif
}
Example #2
0
/* 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();
	}
	
}
Example #3
0
int timer_add_safe(struct timer_ln* tl, ticks_t delta)
#endif
{
	int ret;

	LOCK_TIMER_LIST();
	if (tl->flags & F_TIMER_ACTIVE){
#ifdef TIMER_DEBUG
		LOG(timerlog, "timer_add called on an active timer %p (%p, %p),"
					" flags %x\n", tl, tl->next, tl->prev, tl->flags);
		LOG(timerlog, "WARN: -timer_add-; called from %s(%s):%d\n",
					func, file, line);
		LOG(timerlog, "WARN: -timer_add-: 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("timer_add called on an active timer %p (%p, %p),"
					" flags %x\n", tl, tl->next, tl->prev, tl->flags);
#endif
		ret=-1; /* refusing to add active or non-reinit. timer */
		goto error;
	}
	tl->initial_timeout=delta;
	if ((tl->next!=0) || (tl->prev!=0)){
		LM_CRIT("timer_add: called with linked timer: %p (%p, %p)\n",
				tl, tl->next, tl->prev);
		ret=-1;
		goto error;
	}
	tl->flags|=F_TIMER_ACTIVE;
#ifdef TIMER_DEBUG
	tl->add_file=file;
	tl->add_func=func;
	tl->add_line=line;
	tl->add_calls++;
#endif
	ret=_timer_add(*ticks, tl);
error:
	UNLOCK_TIMER_LIST();
	return ret;
}
Example #4
0
/* called from timer_handle, must be called with the timer lock held
 * WARNING: expired one shot timers are _not_ automatically reinit
 *          (because they could have been already freed from the timer
 *           handler so a reinit would not be safe!) */
inline static void timer_list_expire(ticks_t t, struct timer_head* h
#ifdef USE_SLOW_TIMER
										, struct timer_head* slow_l,
										slow_idx_t slow_mark
#endif
																	)
{
	struct timer_ln * tl;
	ticks_t ret;
#ifdef TIMER_DEBUG
	struct timer_ln* first;
	int i=0;

	first=h->next;
#endif

	/*LM_DBG("@ ticks = %lu, list =%p\n",
			(unsigned long) *ticks, h);
	*/
	while(h->next!=(struct timer_ln*)h){
		tl=h->next;
#ifdef TIMER_DEBUG /* FIXME: replace w/ EXTRA_DEBUG */
		if (tl==0){
			LM_CRIT("timer_list_expire: tl=%p, h=%p {%p, %p}\n",
					tl, h, h->next, h->prev);
			abort();
		}else if((tl->next==0) || (tl->prev==0)){
			LM_CRIT("timer_list_expire: @%d tl=%p "
					"{ %p, %p, %d, %d, %p, %p, %04x, -},"
					" h=%p {%p, %p}\n", t,
					tl,  tl->next, tl->prev, tl->expire, tl->initial_timeout,
					tl->data, tl->f, tl->flags,
					h, h->next, h->prev);
			LM_CRIT("-timer_list_expire-: cycle %d, first %p,"
						"running %p\n", i, first, *running_timer);
			LM_CRIT("-timer_list_expire-: 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);
			abort();
		}
		i++;
#endif
		_timer_rm_list(tl); /* detach */
#ifdef USE_SLOW_TIMER
		if (IS_FAST_TIMER(tl)){
#endif
		/* if fast timer */
			SET_RUNNING(tl);
			tl->next=tl->prev=0; /* debugging */
#ifdef TIMER_DEBUG
			tl->expires_no++;
#endif
			UNLOCK_TIMER_LIST(); /* acts also as write barrier */
				ret=tl->f(t, tl, tl->data);
				/* reset the configuration group handles */
				cfg_reset_all();
				if (ret==0){
					UNSET_RUNNING();
					LOCK_TIMER_LIST();
				}else{
					/* not one-shot, re-add it */
					LOCK_TIMER_LIST();
					if (ret!=(ticks_t)-1) /* ! periodic */
						tl->initial_timeout=ret;
					_timer_add(t, tl);
					UNSET_RUNNING();
				}
#ifdef USE_SLOW_TIMER
		}else{
			/* slow timer */
			SET_SLOW_LIST(tl);
			tl->slow_idx=slow_mark; /* current index */
			/* overflow check in timer_handler*/
			_timer_add_list(slow_l, tl);

		}
#endif
	}
}
Example #5
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;
}
Example #6
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();
	}

}