linux定时器机制,Linux系统内核定时器机制详解(下) (1)

7.6.3.4 将一个定时器插入到链表中

函数add_timer()用来将参数timer指针所指向的定时器插入到一个合适的定时器链表中。它首先调用timer_pending()函数判断所指定的定时器是否已经位于在某个定时器向量中等待执行。如果是,则不进行任何操作,只是打印一条内核告警信息就返回了;如果不是,则调用internal_add_timer()函数完成实际的插入操作。其源码如下(kernel/timer.c):

void add_timer(struct timer_list *timer)

{

unsigned long flags;

spin_lock_irqsave(&timerlist_lock, flags);

if (timer_pending(timer))

goto bug;

internal_add_timer(timer);

spin_unlock_irqrestore(&timerlist_lock, flags);

return;

bug:

spin_unlock_irqrestore(&timerlist_lock, flags);

printk("bug: kernel timer added twice at %p.

",

__builtin_return_address(0));

}

函数internal_add_timer()用于将一个不处于任何定时器向量中的定时器插入到它应该所处的定时器向量中去(根据定时器的expires值来决定)。如下所示(kernel/timer.c):

static inline void internal_add_timer(struct timer_list *timer)

{

/*

* must be cli-ed when calling this

*/

unsigned long expires = timer->expires;

unsigned long idx = expires - timer_jiffies;

struct list_head * vec;

if (idx < TVR_SIZE) {

int i = expires & TVR_MASK;

vec = tv1.vec + i;

} else if (idx < 1 << (TVR_BITS + TVN_BITS)) {

int i = (expires >> TVR_BITS) & TVN_MASK;

vec = tv2.vec + i;

} else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) {

int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;

vec = tv3.vec + i;

} else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {

int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;

vec = 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 = tv1.vec + tv1.index;

} else if (idx <= 0xffffffffUL) {

int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;

vec = tv5.vec + i;

} else {

/* Can only get here on architectures with 64-bit jiffies */

INIT_LIST_HEAD(&timer->list);

return;

}

/*

* Timers are FIFO!

*/

list_add(&timer->list, vec->prev);

}

对该函数的注释如下:

(1)首先,计算定时器的expires值与timer_jiffies的插值(注意!这里应该使用动态定时器自己的时间基准),这个差值就表示这个定时器相对于上一次运行定时器机制的那个时刻还需要多长时间间隔才到期。局部变量idx保存这个差值。

(2)根据idx的值确定这个定时器应被插入到哪一个定时器向量中。其具体的确定方法我们在7.6.2节已经说过了,这里不再详述。最后,定时器向量的头部指针vec表示这个定时器应该所处的定时器向量链表头部。

(3)最后,调用list_add()函数将定时器插入到vec指针所指向的定时器队列的尾部。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值