此文件实现thttpd的定时器功能。
定时器结构:
/* The Timer struct. */
typedef struct TimerStruct {
TimerProc* timer_proc; //响应函数
ClientData client_data; //响应函数参数
long msecs; //定时多长时间
int periodic; //周期性标志
struct timeval time; //定时器触发时间
struct TimerStruct* prev; //哈希表中链表
struct TimerStruct* next;
int hash; //哈希表中主键
} Timer;
定时器保存在全局哈希表中,默认大小(#define HASH_SIZE 67),每个hash节点上的值按照时间顺序排列。
哈希key值:
static unsigned int hash( Timer* t )
{
/* We can hash on the trigger time, even though it can change over
** the life of a timer via either the periodic bit or the tmr_reset()
** call. This is because both of those guys call l_resort(), which
** recomputes the hash and moves the timer to the appropriate list.
*/
return (
(unsigned int) t->time.tv_sec ^
(unsigned int) t->time.tv_usec ) % HASH_SIZE;
}
定时器模块初始化:
static Timer* timers[HASH_SIZE];//散列表
static Timer* free_timers;
static int alloc_count, active_count, free_count;
//定时器模块数据初始化
void tmr_init( void )
{
int h;
for ( h = 0; h < HASH_SIZE; ++h )
timers[h] = (Timer*) 0;
free_timers = (Timer*) 0;
alloc_count = active_count = free_count = 0;
}
单个定时器创建:
Timer* tmr_create(struct timeval* nowP, TimerProc* timer_proc,
ClientData client_data,long msecs, int periodic )
//现在time,定时回调函数,回调函数参数,定时时间,周期性标志
{
Timer* t;
//是否有回收的定时器,如果存在,把要新创建的定时器赋值
if ( free_timers != (Timer*) 0 )
{
t = free_timers;
free_timers = t->next;
--free_count;
}
//不存在,重新创建
else
{
t = (Timer*) malloc( sizeof(Timer) );
if ( t == (Timer*) 0 )
return (Timer*) 0;
++alloc_count;
}
//创建的定时器参数设置
t->timer_proc = timer_proc;
t->client_data = client_data;
t->msecs = msecs;
t->periodic = periodic;
if ( nowP != (struct timeval*) 0 )
t->time = *nowP;
else
(void) gettimeofday( &t->time, (struct timezone*) 0 );
t->time.tv_sec += msecs / 1000L;
t->time.tv_usec += ( msecs % 1000L ) * 1000L;
if ( t->time.tv_usec >= 1000000L )
{
t->time.tv_sec += t->time.tv_usec / 1000000L;
t->time.tv_usec %= 1000000L;
}
//生成hash的K值
t->hash = hash( t );
/* Add the new timer to the proper active list. */
//加入hash表
l_add( t );
++active_count;
return t;
}
把创建的定时器加入hash表:
//创建的timer加入hash表
static void l_add( Timer* t )
{
int h = t->hash;
Timer* t2;
Timer* t2prev;
t2 = timers[h];
//如果h主键的timer链表没有timer
if ( t2 == (Timer*) 0 )
{
/* The list is empty. */
timers[h] = t;
t->prev = t->next = (Timer*) 0;
}
//存在
else
{
//注:在K值的timer链表中,是按照触发时间小到大排序
//加入的timer触发时间小于K值链表中的第一个timer触发时间
if ( t->time.tv_sec < t2->time.tv_sec ||
( t->time.tv_sec == t2->time.tv_sec &&
t->time.tv_usec <= t2->time.tv_usec ) )
{
/* The new timer goes at the head of the list. */
timers[h] = t;
t->prev = (Timer*) 0;
t->next = t2;
t2->prev = t;
}
else
{
/* Walk the list to find the insertion point. */
//插入中间合适位置,依次比较
for ( t2prev = t2, t2 = t2->next; t2 != (Timer*) 0; t2prev = t2, t2 = t2->next )
{
if ( t->time.tv_sec < t2->time.tv_sec ||
( t->time.tv_sec == t2->time.tv_sec && t->time.tv_usec <= t2->time.tv_usec ) )
{
/* Found it. */
t2prev->next = t;
t->prev = t2prev;
t->next = t2;
t2->prev = t;
return;
}
}
/* Oops, got to the end of the list. Add to tail. */
t2prev->next = t;
t->prev = t2prev;
t->next = (Timer*) 0;
}
}
}
使用while循环tmr_run()查找超时的定时器:
//查找定时间到了的定时器,
//产生回调
//设置参数或者消除
void tmr_run( struct timeval* nowP )
{
int h;
Timer* t;
Timer* next;
for ( h = 0; h < HASH_SIZE; ++h )
for ( t = timers[h]; t != (Timer*) 0; t = next )
{
next = t->next;
/* Since the lists are sorted, as soon as we find a timer
** that isn't ready yet, we can go on to the next list.
*/
if ( t->time.tv_sec > nowP->tv_sec ||
( t->time.tv_sec == nowP->tv_sec &&
t->time.tv_usec > nowP->tv_usec ) )
break;//定时时间未到,继续查找
//定时时间到
(t->timer_proc)( t->client_data, nowP );//调用回调函数
if ( t->periodic )//如果周期性,设置时间参数,并重新加入hash表
{
/* Reschedule. */
t->time.tv_sec += t->msecs / 1000L;
t->time.tv_usec += ( t->msecs % 1000L ) * 1000L;
if ( t->time.tv_usec >= 1000000L )
{
t->time.tv_sec += t->time.tv_usec / 1000000L;
t->time.tv_usec %= 1000000L;
}
l_resort( t );
}
else//消除
tmr_cancel( t );
}
}
void tmr_reset( struct timeval* nowP, Timer* timer )//重新开始运行定时器,时钟设置为当前时间nowP加上定时时长
//释放定时器,由于tmr_run中对所有非周期性定时器都已经调用tmr_cancel,用户无需再自己对非周期定时器调用
//将timers加入free_timers链表,节省free和malloc的开销,相当于一个缓冲池
void tmr_cancel( Timer* timer )
//清空定时器包,释放所有无用的内存:free_timers链表
void tmr_cleanup( void )
//调用tmr_cancel释放所有定时器,为退出做准备,
void tmr_destroy( void )
//生成调试log信息,记录当前已分配、使用中、free的定时器个数
void tmr_logstats( long secs )