这个函数的注释如下:
/**
*__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; }