/* 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
/* 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");
}
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();
	}

}