struct timer_list
|-----------------------------------|
|struct list_head entry |
|unsigned long expires |
|void (*function)(unsigned long)|
|unsigned long data |
|struct tvec_t_base_s *base |--+
|-----------------------------------| -|
|void *start_site | -| CONFIG_TIMER_STATS
|char start_comm[16]| -|
|int start_pid | -|
|-----------------------------------| -|
|
+--------------------------------------+
| 时钟向量base结构tvec_t_base_s
| struct tvec_t_base_s
+-->|---------------------------------|
|spinlock_t lock |
|struct timer_list *running_timer |
|unsigned long timer_jiffies -| base的基准时间
|tvec_root_t tv1 | root hash链表
|tvec_t tv2 | 二级hash链表
|tvec_t tv3 | 三级hash链表
|tvec_t tv4 | 四级hash链表
|tvec_t tv5 | 五级hash链表
|---------------------------------|
____cacheline_aligned_in_smp
expires 定时器定时的滴答数(当前的滴答数为jiffies)
function 到那个时刻内核调用的函数
data 由于可能多个定时器调用一个函数,为了使得这个函数能够区分不同的定时器,通过在结构中data来标识这个定时器,并且通过调用 function(data)使得function能区分它们,也就是 data起到ID的作用。
使用时钟,先声明一个timer_list结构,调用init_timer对它进行初始化。 time_list结构里expires是标明这个时钟的周期,单位采用jiffies的单位。function就是时间到了以后的回调函数,它的参数就 是timer_list中的data。 data这个参数在初始化时钟的时候赋值,一般赋给它设备的device结构指针。在预置时间到系统调用function,同时系统把这个 time_list从定时队列里清除。所以如果需要一直使用定时函数,要在function里再次调用add_timer()把这个timer_list 加进定时队列。
管理定时器的接口----------------------------------------------------------
创建定时器需要先定义它:
struct timer_list my_timer;
接着需要通过一个辅助函数初始化定时器数据结构的内部值,初始化必须在使用其他定时器管理函数对定时器进行操作前完成。
init_timer(&my_timer);
现在可以填充结构中需要的值了(与定时器直接相关的三个参数):
my_timer.expires = jiffies + delay; // 定时器超时时的节拍数
my_timer.data = 0; // 给定时器处理函数传入参数0
my_timer.function = my_function; // 定时器超时时调用的函数
my_timer.expires表示超时时间,它是以节拍为单位的绝对计数值。如果当前jiffies计数等于或大于 my_timer.expires,那么my_function指向的处理函数就会开始执行,另外该函数还要使用长整型参数my_timer.data。 如果你不需要这个参数,可以简单地传递0(或任何其他值)给处理函数。
最后,必须激活定时器:
add_timer(&my_timer);
大功告成,定时器可以工作了!但请注意定时值的重要性。当前节拍计数大于或等于指定的超时值时,内核就开始执行定时器处理函数。虽然内核可以保证不会在超时时间到期前运行定时器处理函数,但是有可能延误定时器的执行。一般来说,定时器都在超时后马上就回执行,但是也有可能被推迟到一下时钟节拍才能运行,所以不能用定时器来实现任何硬实时任务。
有时可能需要更改已经激活的定时器超时时间,所以内核通过函数mod_timer()来实现该功能,该函数可以改变指定的定时器超时时间:
mod_timer(&my_timer, jiffies+new_delay);
mod_timer()函数也可操作那些已经初始化,但还没有被激活的定时器,如果定时器未被激活,mod_timer()会激活它。如果调用时定时器未被激活,该函数返回0;否则返回1。但不论哪种情况,一旦从mod_timer()函数返回,定时器都将被激活而且设置了新的定时值。
如果需要在定时器超时前停止定时器,可以使用del_timer()函数:
del_timer(&my_timer);
被激活或未被激活的定时器都可以使用该函数,如果定时器还未被激活,该函数返回0;否则返回1。注意,你不需要为已经超时的定时器调用该函数,因为它们超时后会自动被删除。
当删除定时器时,必须小心一个潜在的竞争条件。当del_timer()返回后,可以保真的只是: 定时器不会再被激活(也就是,将来不会执行),但是在多处理机器上定时器中断可能已经在其他处理器上运行了,所以删除定时器时需要等待可能在其他处理器上 运行的定时器处理程序都退出,这时就要使用del_timer_sync()函数执行删除工作:
del_timer_sync(&my_timer);
和del_timer()函数不同,del_timer_sync()函数不能在中断上下文中使用。
tvec_t, tvec_root_t hash链表 <%2
阅读(1042) | 评论(0) | 转发(0) |