科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件Linux系统内核定时器机制详解(下) (1)

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

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

函数add_timer()用来将参数timer指针所指向的定时器插入到一个合适的定时器链表中。

作者:赛迪网技术社区 来源:赛迪网技术社区 2007年10月26日

关键字: 定时器 内核 Linux

  • 评论
  • 分享微博
  • 分享邮件
 

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指针所指向的定时器队列的尾部。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章