Linux的动态定时器(2)

1、 if(timer_pending(timer) && timer->expires == expires)

return1;

如果该timer已经在已经加入了timer_base中的某个向量(tv1—tv5)中,函数什么也不做,直接返回。

2、__mod_timer(timer,expires, false, TIMER_NOT_PINNED);

这个函数的关键代码:

timer->expires = expires;   if (time_before(timer->expires, base->next_timer) &&       !tbase_get_deferrable(timer->base))       base->next_timer = timer->expires;   internal_add_timer(base, timer);  

internal_add_timer(base,timer);函数完成实际的添加操作:

static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)   {       unsigned long expires = timer->expires;       unsigned long idx = expires - base->timer_jiffies;       struct list_head *vec;          if (idx < TVR_SIZE) {           int i = expires & TVR_MASK;           vec = base->tv1.vec + i;       } else if (idx < 1 << (TVR_BITS + TVN_BITS)) {           int i = (expires >> TVR_BITS) & TVN_MASK;           vec = base->tv2.vec + i;       } else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) {           int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;           vec = base->tv3.vec + i;       } else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {           int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;           vec = base->tv4.vec + i;       } else if ((signed long) idx < 0) {           /*           * Can happen if you add a timer with expires == jiffies,           * or you set a timer to go off in the past           */           vec = base->tv1.vec + (base->timer_jiffies & TVR_MASK);       } else {           int i;           /* If the timeout is larger than 0xffffffff on 64-bit           * architectures then we use the maximum timeout:           */           if (idx > 0xffffffffUL) {               idx = 0xffffffffUL;               expires = idx + base->timer_jiffies;           }           i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;           vec = base->tv5.vec + i;       }       /*       * Timers are FIFO:       */       list_add_tail(&timer->entry, vec);   }  

internal_add_timer函数仔细分析:

1、

        unsigned long expires = timer->expires;       unsigned long idx = expires - base->timer_jiffies;       struct list_head *vec;  

unsignedlong expires = timer->expires;这个是该定时器定的时间,

而base->timer_jiffies表示需要检查的动态定时器的最早到期时间。

那么unsignedlong idx = expires - base->timer_jiffies;

他们的差值表示表示这个新插入的定时器相对于最早到期的定时器还需要多长时间间隔才到期。

差值越大,这个定时器的处理可以放后,差值越小,这个定时器就越被关心。

2、

if (idx < TVR_SIZE) {           int i = expires & TVR_MASK;           vec = base->tv1.vec + i;       } else if (idx < 1 << (TVR_BITS + TVN_BITS)) {           int i = (expires >> TVR_BITS) & TVN_MASK;           vec = base->tv2.vec + i;       } else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) {           int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;           vec = base->tv3.vec + i;       } else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {           int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;           vec = base->tv4.vec + i;       } else if ((signed long) idx < 0) {           /*           * Can happen if you add a timer with expires == jiffies,           * or you set a timer to go off in the past           */           vec = base->tv1.vec + (base->timer_jiffies & TVR_MASK);       } else {           int i;           /* If the timeout is larger than 0xffffffff on 64-bit           * architectures then we use the maximum timeout:           */           if (idx > 0xffffffffUL) {               idx = 0xffffffffUL;               expires = idx + base->timer_jiffies;           }           i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;           vec = base->tv5.vec + i;       }

这一步就是根据idx的值,来确定这个定时器该插入哪个级别的定时器向量中:tv1--tv5.

举两个例子,如果idx= 240;那么表明这个定时器在接下来的256个jiffies单位中就会被处理,将它加入到tv1中:

if(idx < TVR_SIZE) {

inti = expires & TVR_MASK;

vec= base->tv1.vec + i;

}


如果idx在256和19384之间,则将它加入到tv2中:

elseif (idx < 1 << (TVR_BITS + TVN_BITS)) {

inti = (expires >> TVR_BITS) & TVN_MASK;

vec= base->tv2.vec + i;

}

只要(expires>> TVR_BITS) & TVN_MASK值相同的定时器放在tv2下的同一个链表中。

依此类推。

这个地方再仔细想一想:因为按照idx的间隔大小做了区分,那tv1--tv5中每个数组的链表的长度是有限定的:

数组大小     每个数组的链表的粒度

tv1: 256                           1

tv2: 64                             2<<8 =256

tv3: 64                             2<<(8+6)= 16384

tv4: 64                             2<<(8+2*6)=1048576

tv5: 64                             2<<(8+3*6)=67108864

在tv1中,每个链表头只能包含时间相同的定时器。

而在tv2中,64个数组项中的每个链表中都可以包含256个连续的定时长度的定时器。(当然对于每个定时长度,可以有多个定时器)

其实,这些都是部分排序的,比如tv2中的第一个数组中的链表的所有定时器肯定比第二个数组中的链表的任一个定时器小,但第一个数组中的链表中的定时器不一定是排好序的。tv1中的定时器<tv2<tv3<tv4<tv5.

总的加起来,也可以表示2^32的时间范围。这里才用了256+64+64+64+64 = 256 个链表头。

3、list_add_tail(&timer->entry,vec);

将这个定时器timer内嵌的list_head(entry)加入到上面确定的timer向量vec的尾部。

接下来,我们来分析动态定时器的执行:

再回头看看最开始定时器初始化部分中提到的定时器中断服务函数:

run_timer_softirq

/*   * This function runs timers and the timer-tq in bottom half context.   */   static void run_timer_softirq(struct softirq_action *h)   {       struct tvec_base *base = __get_cpu_var(tvec_bases);          hrtimer_run_pending();          if (time_after_eq(jiffies, base->timer_jiffies))           __run_timers(base);   }  

if(time_after_eq(jiffies, base->timer_jiffies))

__run_timers(base);

当当前系统的jiffies大于或等于base->timer_jiffies(动态定时器中的最早到期时间)时,就会运行__run_timers(base);

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

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