Linux的动态定时器(3)

这个函数的注释如下:

/**

*__run_timers - run all expired timers (if any) on this CPU.

*@base: the timer vector to be processed.

*

*This function cascades all vectors andexecutes all expired timer

*vectors.

*/

__run_timers会将所有的定时器向量层叠起来,执行到期的定时器向量。

__run_timers的执行核心如下:

pin_lock_irq(&base->lock);       while (time_after_eq(jiffies, base->timer_jiffies)) {           struct list_head work_list;           struct list_head *head = &work_list;           int index = base->timer_jiffies & TVR_MASK;              /*           * 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);                  set_running_timer(base, timer);               detach_timer(timer, 1);  

spin_lock_irq(&base->lock);

获取自旋锁并禁止本地中断;

进入while循环while(time_after_eq(jiffies, base->timer_jiffies))

当base->timer_jiffies大于jiffies时候,while循环才会终止。

每一次循环的各个子步骤:

A、 structlist_head work_list;

struct list_head *head =&work_list;

intindex = base->timer_jiffies & TVR_MASK;

获取base->tv1中的索引index,如果index的值等于0,说明tv1中各个数组项都

已经执行过了,需要从tv2中将base->tv2.vec+1这个桶中的定时器搬移到tv1中,因为随着时间的推移,tv2中第1个桶中(包含还有256到511才到期的,而tv2的桶编号是第0个桶到第63个桶,因为tv1中包含0到255到期的,tv2的第0个桶是空的,实际上在添加定时器的时候,tv2 tv3 tv4的第0个桶不可能有定时器,因为不可能在保证差值的情况下还保证那个hash用到的索引值等于0;以下面的第一张图:tv3中的桶的粒度16k = 63*256 (tv2的63个桶)+ 256*1(tv1的256个桶))

需要说明的是,每次执行__run_timers是将tv2中某个桶的定时器搬移到tv1中,但最开始是从第一个桶开始的。

上面的index是tv1的索引

INDEX(0)是tv2的索引

INDEX(1)是tv3的索引

INDEX(2)是tv4的索引

INDEX(3)是tv5的索引

给出INDEX的宏定义:

#defineINDEX(N) ((base->timer_jiffies >> (TVR_BITS + (N) *TVN_BITS)) & TVN_MASK)

这几个和index的用法是类似的。

将tv2的某个桶的定时器搬移到tv1中是用casecade函数完成的:

cascade(base,&base->tv2, INDEX(0))   staticint cascade(struct tvec_base *base, struct tvec *tv, int index)   {   /*cascade all the timers from tv up one level */   structtimer_list *timer, *tmp;   structlist_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);   }      returnindex;   }  

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/pssxw.html