thttpd源码之Timers.c

此文件实现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 )

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值