Chinaunix首页 | 论坛 | 博客
  • 博客访问: 724298
  • 博文数量: 104
  • 博客积分: 4320
  • 博客等级: 上校
  • 技术积分: 1948
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-30 14:42
文章分类

全部博文(104)

文章存档

2012年(4)

2011年(65)

2010年(35)

分类: LINUX

2010-07-28 16:19:25

        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) |
给主人留下些什么吧!~~