可见涉及到系统定时器的数据结构并不多,那么:对于一个linux系统中,定时器个数可能会很多,而且每个定时器的超时事件时间并不相同,所以如何管理和处理定时器超时事件,关系到内核性能的高低。它根据不同的定时事件,按时间间分组,将新增的timer定时器建成双向链表,然后按照一定方式存放于5组tv1~tv5变量中称为tec_base。对于对称式多理器(SMP)系统还考虑到了TIMER从一个CPU迁移到另一个CPU的情况,相应的tev_base也跟着更改。那它在系统是怎样实现的呢?现在先从一个简单的系统定时器应用例子来看看它的实现过程:
[cpp]
#include
#include
#include
structtimer_list my_timer;
staticvoidmy_function(unsignedlongdata)
{
staticinti = 0;
printk("timer’s callback function\n");
printk("timer’s data = %lu\n",data);
return;
}
staticintmy_timer_init(void)
{
printk(“timerinit…\n”);
my_timer.data = 0xff;
my_timer.function = my_function;
my_timer.expires = jiffies + 3*HZ;
init_timer(&my_timer);
add_timer(&my_timer);
return0;
}
staticvoidmy_timer_exit(void)
{
printk("timer exit…\n");
}
module_init(my_timer_init);
module_exit(my_timer_exit);
MODULE_AUTHOR("itspy");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("linux kernel timerprogramming");
上面例子,实现了一个定时器事件,将在3 HZ(秒)发生。my_imer_init函数中调用到的定时器API只有:
init_timer(&my_timer); //用于定时器初始化
add_timer(&my_timer); //增加一个新的定时器到tev_base向量表中
其中init_timer中调用了__init_timer(),这个函数才是真正初始化定时器的:
[cpp]
staticvoid__init_timer(structtimer_list*timer,
constchar*name,
structlock_class_key *key)
{
timer->entry.next= NULL;//对于新增的timer实例,其下一各总是指向NULL。
timer->base= __raw_get_cpu_var(tvec_bases);//SMP中,获得当前处理器的tev_base
//这个tev_bases是根据一定规律变化的,稍后会将到
…
}
新增的定时器初始化,就是完成了一个timer_list结构初始化过程。
add_timer() --> mod_timer() --> __mod_timer()其中:
[cpp]
staticinlineint
__mod_timer(structtimer_list *timer,unsignedlongexpires,boolpending_only)
{
structtvec_base *base, *new_base;
unsignedlong flags;
intret;
ret= 0;
BUG_ON(!timer->function);// BUG检测,确保回调函数为非空NULL
base= lock_timer_base(timer, &flags);//获取本地cpu的tev_base,这是一个临
//界资源,里边是一个for(;;)循环,如果找不到说明已经迁移到了别的CPU
if(timer_pending(timer)) {//当已挂载的timer 定时超时发生后,会被卸载摘除
detach_timer(timer,0);
ret= 1;
}else{
if(pending_only)//新增一个定时器时,pending_only 为 false
gotoout_unlock;
}
…
new_base= __get_cpu_var(tvec_bases);//获取本地cpu中的tevc_bases
if(base != new_base) {//由于之前base 可能已被迁移到其他CPU的 tev_base向量表,会造成 base != new_base
if(likely(base->running_timer != timer)) {//由于在timer正在运行时,我们不能直接更改base,位与一个叫做DEFERRABLE(可延后标志)后处理
/*See the comment in lock_timer_base() */
timer_set_base(timer,NULL);
spin_unlock(&base->lock);
base= new_base;
spin_lock(&base->lock);
timer_set_base(timer,base);
}
}
timer->expires= expires;
internal_add_timer(base,timer);//分析timer expires及建表过程
out_unlock:
spin_unlock_irqrestore(&base->lock,flags);
returnret;
}