modules/tm/timer.c
7611117f
 /*
  * $Id$
  */
 
 
dda9dab1
 #include "config.h"
 #include "h_table.h"
d214be66
 #include "timer.h"
ca6852b2
 #include "../../dprint.h"
d214be66
 
d3b31abd
 int timer_group[NR_OF_TIMER_LISTS] = { 
 	TG_FR, TG_FR,
 	TG_WT,
 	TG_DEL,
 	TG_RT, TG_RT, TG_RT, TG_RT
 };
 
dda9dab1
 void reset_timer_list( struct s_table* hash_table, enum lists list_id)
 {
 	hash_table->timers[ list_id ].first_tl.next_tl = & (hash_table->timers[ list_id ].last_tl );
 	hash_table->timers[ list_id ].last_tl.prev_tl = & (hash_table->timers[ list_id ].first_tl );
 	hash_table->timers[ list_id ].first_tl.prev_tl = 
 		hash_table->timers[ list_id ].last_tl.next_tl = NULL;
 	hash_table->timers[ list_id ].last_tl.time_out = -1;
 }
4c69201e
 
dda9dab1
 void init_timer_list( struct s_table* hash_table, enum lists list_id)
 {
 	reset_timer_list( hash_table, list_id );
 	init_timerlist_lock( hash_table, list_id );
 }
 
 void print_timer_list(struct s_table* hash_table, enum lists list_id)
e057a62e
 {
    struct timer* timer_list=&(hash_table->timers[ list_id ]);
    struct timer_link *tl ;
 
dda9dab1
    tl = timer_list->first_tl.next_tl;
    while (tl!=& timer_list->last_tl)
e057a62e
    {
       DBG("DEBUG: print_timer_list[%d]: %p, next=%p \n",list_id, tl, tl->next_tl);
       tl = tl->next_tl;
    }
 }
 
d3b31abd
 /* static void remove_from_timer_list_dummy(  struct timer_link* tl ) */
 void remove_timer_unsafe(  struct timer_link* tl )
df51b111
 {
40a8d9dd
 #ifdef EXTRA_DEBUG
 	if (tl && tl->timer_list &&
 		tl->timer_list->last_tl.prev_tl==0) {
 		LOG( L_CRIT,
 		"CRITICAL : Oh no, zero link in trailing timer element\n");
 		abort();
 	};
 #endif
 
 
d3b31abd
 	if (is_in_timer_list2( tl )) {
 		tl->prev_tl->next_tl = tl->next_tl;
 		tl->next_tl->prev_tl = tl->prev_tl;
 		tl->next_tl = 0;
 		tl->prev_tl = 0;
 		tl->timer_list = NULL;
 	}
df51b111
 }
 
dda9dab1
 /* put a new cell into a list nr. list_id within a hash_table;
   * set initial timeout
   */
d3b31abd
 void add_timer_unsafe( struct timer *timer_list,
dda9dab1
 	struct timer_link *tl, unsigned int time_out )
 {
40a8d9dd
 #ifdef EXTRA_DEBUG
 	if (timer_list->last_tl.prev_tl==0) {
 	LOG( L_CRIT,
 		"CRITICAL : Oh no, zero link in trailing timer element\n");
 		abort();
 	};
 #endif
 
d3b31abd
 	/*	remove_from_timer_list( tl ); */
dda9dab1
 	/* the entire timer list is locked now -- noone else can manipulate it */
657a5566
 	/* lock( timer_list->mutex ); */
dda9dab1
 	tl->time_out = time_out;
 	tl->prev_tl = timer_list->last_tl.prev_tl;
 	tl->next_tl = & timer_list->last_tl;
 	timer_list->last_tl.prev_tl = tl;
 	tl->prev_tl->next_tl = tl;
d3b31abd
 	tl->timer_list = timer_list;
 #	ifdef EXTRA_DEBUG
 		if ( tl->tg != timer_group[ timer_list->id ] ) {
 			LOG( L_CRIT, "CRITICAL error: changing timer group\n");
 			abort();
 		}
 #	endif
dda9dab1
 	/* give the list lock away */
657a5566
 	/* unlock( timer_list->mutex ); */
dda9dab1
 	DBG("DEBUG: add_to_tail_of_timer[%d]: %p\n",timer_list->id,tl);
 }
df51b111
 
dda9dab1
 /*
 	detach items passed by the time from timer list
 */
 struct timer_link  *check_and_split_time_list( struct timer *timer_list, int time )
 
 {
 	struct timer_link *tl , *tmp , *end, *ret;
 
ea6721d7
 	/* quick check whether it is worth entering the lock */
 	if (timer_list->first_tl.next_tl==&timer_list->last_tl ||
 		timer_list->first_tl.next_tl->time_out > time )
 			return NULL;
 
dda9dab1
 	/* the entire timer list is locked now -- noone else can manipulate it */
657a5566
 	lock(timer_list->mutex);
dda9dab1
 
 	end = &timer_list->last_tl;
 	tl = timer_list->first_tl.next_tl;
d3b31abd
 	while( tl!=end && tl->time_out <= time) {
 		tl->timer_list = NULL;
 		tl=tl->next_tl;
 	}
dda9dab1
 
 	/* nothing to delete found */
 	if (tl->prev_tl==&(timer_list->first_tl)) {
 		ret = NULL;
 	} else { /* we did find timers to be fired! */
 		/* the detached list begins with current beginning */
 		ret = timer_list->first_tl.next_tl;
 		/* and we mark the end of the split list */
 		tl->prev_tl->next_tl = NULL;
 		/* the shortened list starts from where we suspended */
 		timer_list->first_tl.next_tl = tl;	
 		tl->prev_tl = & timer_list->first_tl;
 	}
40a8d9dd
 #ifdef EXTRA_DEBUG
 	if (timer_list->last_tl.prev_tl==0) {
 		LOG( L_CRIT,
 		"CRITICAL : Oh no, zero link in trailing timer element\n");
 		abort();
 	};
 #endif
 
e057a62e
 
b13b5342
    /* give the list lock away */
657a5566
    unlock(timer_list->mutex);
dda9dab1
 
    return ret;
d214be66
 }
7298c786
 
 
 
e2c3f08c
 
dda9dab1
 
 void timer_routine(unsigned int ticks , void * attr)
 {
 	struct s_table       *hash_table = (struct s_table *)attr;
 	struct timer*          timers= hash_table->timers;
 	struct timer_link  *tl, *tmp_tl;
 	int                           id;
 
 
 	for( id=0 ; id<NR_OF_TIMER_LISTS ; id++ )
 	{
 		/* to waste as little time in lock as possible, detach list
 		   with expired items and process them after leaving the
 		   lock
 		*/
 		tl = check_and_split_time_list( & (hash_table->timers[ id ]), ticks );
 		/* process items now */
 		while (tl)
 		{
 			/* reset the timer list linkage */
 			tmp_tl = tl->next_tl;
 			tl->next_tl = tl->prev_tl =0 ; 
 			DBG("DEBUG: timer routine: timer[%d] , tl=%p next=%p\n",id,tl,tmp_tl);
 			timers[id].timeout_handler( tl->payload );
 			tl = tmp_tl;
 		}
 	}
 }