基于链表实现的定时器可以定义为:
清单 3. 基于链表的定时器定义
typedef int timer_id;
/**
* The type of callback function to be called by timer scheduler when a timer
* has expired.
*
* @param id The timer id.
* @param user_data The user data.
* $param len The length of user data.
*/
typedef int timer_expiry(timer_id id, void *user_data, int len);
/**
* The type of the timer
*/
struct timer {
LIST_ENTRY(timer) entries;/**< list entry */
timer_id id; /**< timer id */
int interval; /**< timer interval(second) */
int elapse; /**< 0 -> interval */
timer_expiry *cb; /**< call if expiry */
void *user_data; /**< callback arg */
int len; /**< user_data length */
};
定时器的时间间隔以 interval 表示,而 elapse 则在 PerTickBookkeeping() 时递增,直到 interval 表示定时器中止,此时调用回调函数 cb 来执行相关的行为,而 user_data 和 len 为用户可以传递给回调函数的参数。
所有的定时器实例以链表来管理:
清单 4. 定时器链表
/**
* The timer list
*/
struct timer_list {
LIST_HEAD(listheader, timer) header; /**< list header */
int num; /**< timer entry number */
int max_num; /**< max entry number */
void (*old_sigfunc)(int); /**< save previous signal handler */
void (*new_sigfunc)(int); /**< our signal handler */
struct itimerval ovalue; /**< old timer value */
struct itimerval value; /**< our internal timer value */
};
这里关于链表的实现使用了 BSD 风格关于链表的一组宏,避免了再造轮子;该结构中,old_sigfunc 在 init_timer 初始定时器链表时候用来保存系统对 SIGALRM 的处理函数,在定时器系统 destory 时用来恢复到之前的处理函数; ovalue 的用途与此类似。
清单 5. 定时器链表的创建和 Destroy
/**
* Create a timer list.
*
* @param count The maximum number of timer entries to be supported initially.
*
* @return 0 means ok, the other means fail.
*/
int init_timer(int count)
{
int ret = 0;
if(count <=0 || count > MAX_TIMER_NUM) {
printf("the timer max number MUST less than %d.\n", MAX_TIMER_NUM);
return -1;
}
memset(&timer_list, 0, sizeof(struct timer_list));
LIST_INIT(&timer_list.header);
timer_list.max_num = count;
/* Register our internal signal handler and store old signal handler */
if ((timer_list.old_sigfunc = signal(SIGALRM, sig_func)) == SIG_ERR) {
return -1;
}
timer_list.new_sigfunc = sig_func;
/*Setting our interval timer for driver our mutil-timer and store old timer value*/
timer_list.value.it_value.tv_sec = TIMER_START;
timer_list.value.it_value.tv_usec = 0;
timer_list.value.it_interval.tv_sec = TIMER_TICK;
timer_list.value.it_interval.tv_usec = 0;
ret = setitimer(ITIMER_REAL, &timer_list.value, &timer_list.ovalue);
return ret;
}
/**
* Destroy the timer list.
*
* @return 0 means ok, the other means fail.
*/
int destroy_timer(void)
{
struct timer *node = NULL;
if ((signal(SIGALRM, timer_list.old_sigfunc)) == SIG_ERR) {
return -1;
}
if((setitimer(ITIMER_REAL, &timer_list.ovalue, &timer_list.value)) < 0) {
return -1;
}
while (!LIST_EMPTY(&timer_list.header)) { /* Delete. */
node = LIST_FIRST(&timer_list.header);
LIST_REMOVE(node, entries);
/* Free node */
printf("Remove id %d\n", node->id);
free(node->user_data);
free(node);
}
memset(&timer_list, 0, sizeof(struct timer_list));
return 0;
}