linux时间子系统(六)

3.1.4 定时器处理 编程

static inline void __run_timers(struct tvec_base *base)数组

{函数

        struct timer_list *timer;post

 

        spin_lock_irq(&base->lock);spa

        while (time_after_eq(jiffies, base->timer_jiffies)) {指针

                struct list_head work_list;orm

                struct list_head *head = &work_list;索引

                int index = base->timer_jiffies & TVR_MASK;事件

 

                /*ci

                 * Cascade timers:

                 */

                if (!index &&

                        (!cascade(base, &base->tv2, INDEX(0))) &&

                                (!cascade(base, &base->tv3, INDEX(1))) &&

                                        !cascade(base, &base->tv4, INDEX(2)))

                        cascade(base, &base->tv5, INDEX(3));

                ++base->timer_jiffies;

                list_replace_init(base->tv1.vec + index, &work_list);

                while (!list_empty(head)) {

                        void (*fn)(unsigned long);

                        unsigned long data;

 

                        timer = list_first_entry(head, struct timer_list,entry);

                        fn = timer->function;

                        data = timer->data;

 

                        timer_stats_account_timer(timer);

 

                        base->running_timer = timer;

                        detach_timer(timer, 1);

 

                        spin_unlock_irq(&base->lock);

                        call_timer_fn(timer, fn, data);

                        base->running_timer = NULL;

                        spin_lock_irq(&base->lock);

                }

        }

        wake_up(&base->wait_for_running_timer);

        spin_unlock_irq(&base->lock);

}

 

static int cascade(struct tvec_base *base, struct tvec *tv, int index)

{

        /* cascade all the timers from tv up one level */

        struct timer_list *timer, *tmp;

        struct list_head tv_list;

 

        list_replace_init(tv->vec + index, &tv_list);

 

        /*              

         * We are removing _all_ timers from the list, so we

         * don't have to detach them individually.

         */             

        list_for_each_entry_safe(timer, tmp, &tv_list, entry) {

                BUG_ON(tbase_get_base(timer->base) != base);

                internal_add_timer(base, timer);

        }       

        

        return index;

}

   当前cpu的tvec_base.timer_jiffies的低8位不为0时,按tv1-tv5组成的32位数作加法运算来看,tv1到tv2没有发生进位,因此能够直接处理tvec_base.timer_jiffies的低8位做为下标索引的tv1中的定时器链表中的定时器便可。此时调用定时器的回调函数处理便可。而当tvec_base.timer_jiffies的低8位为0时,代表发生了进位,此时须要从高一级别的tv2中取出((base->timer_jiffies >> (TVR_BITS + (0) * TVN_BITS)) & TVN_MASK)做为索引下标的链表,使用函数internal_add_timer将链表中的数组逐一添加到tv1中。当低14位全为0时,代表tv1向tv2进位,tv2向tv3进位,此时,先完成tv2向tv1的迁移,在完成tv3到tv2的迁移。后续过程依次类推。

3.1.5 定时器的使用 

  在使用定时器以前,咱们须要知道如何定义定时器。在内核编程中使用定时器,首先咱们须要定义一个time_list结构

3.1.5.1 timer_list结构

struct timer_list {

        /*

         * All fields that change during normal runtime grouped to the

         * same cacheline

         */     

        struct list_head entry;

        unsigned long expires;

        struct tvec_base *base;

            

        void (*function)(unsigned long);

        unsigned long data;

         

        int slack;

.....

}

entry,用于把一组定时器组成一个链表。

expires,定时器的到期时刻。也就是定时器到期时刻的jiffies计数值。

base,每一个cpu拥有一个本身的用于管理定时器的tvec_base结构。该字段指向定时器所属cpu所对应的tvec_base结构。

function,函数指针。定时器到期时,系统会调用该回调函数,用于响应定时器的到期事件。

data,function回调函数的参数。

slack,对有些对到期时间精度不太敏感的定时器,到期时刻容许适当的延迟一小段时间。该字段用于计算每次延迟的HZ数。

3.1.5.2 定义timer_list 

  要定义一个定时器,能够使用静态动态两种方案。静态方案使用DEFINE_TIMER宏,代码以下:

#define DEFINE_TIMER(_name, _function, _expires, _data)

   该宏将获得一个名字为_name,回调函数为_function,回调函数参数为_data,到期时刻为_expires的timer_list结构。

 

  若是使用动态方法,能够本身声明一个timer_list结构,以后手动初始化其相关字段,代码以下:

struct timer_list timer;

init_timer(&timer);

timer.function=_function;

timer.expires=_expires;

timer.data=_data;

3.1.5.3 激活定时器

  能够使用add_timer(&timer)激活一个定时器。

3.1.5.4 修改定时器到期时间

  能够使用mod_timer(&timer, new_expires)修改定时器到期时间。

3.1.5.5 移除定时器 

  使用函数del_timer(&timer)移出定时器。

3.1.5.6 延迟处理 

  对于某些对精度不敏感的定时器,咱们能够设定timer_list.slack字段的值,设定timer容许到期时刻的最大延迟。使用函数set_timer_slack(&timer, slack_hz)能够完成目标。

相关文章
相关标签/搜索