Linux系统内核定时器机制详解(下)(1)
文章作者 100test 发表时间 2007:03:14 16:45:02
来源 100Test.Com百考试题网
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.\n",
__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指针所指向的定时器队列的尾部。