Linux 2.4.35 时钟中断分析(续)
在上一篇文章中,我们跟踪到了timer_bh()这个函数。timer_bh()是时钟中断的下半部,是一个软中断,它位于Timer.c:
void timer_bh(void)
{
update_times();
run_timer_list();
}
|
从代码可以看出,它主要有两个任务,一个是update_times(),另一个是run_timer_list()。update_times()主要任务是更新系统时间,同时还计算系统的负载情况,这里不做详细分析。下面来看看run_timer_list()是干什么的:
static inline void run_timer_list(void)
{
spin_lock_irq(&timerlist_lock);
while ((long)(jiffies - timer_jiffies) >= 0) {
LIST_HEAD(queued);
struct list_head *head, *curr;
if (!tv1.index) {
int n = 1;
do {
cascade_timers(tvecs[n]);
} while (tvecs[n]->index == 1 && ++n < NOOF_TVECS);
}
run_timer_list_running = &queued;
repeat:
head = tv1.vec + tv1.index;
curr = head->next;
if (curr != head) {
struct timer_list *timer;
void (*fn)(unsigned long);
unsigned long data;
timer = list_entry(curr, struct timer_list, list);
fn = timer->function;
data= timer->data;
detach_timer(timer);
timer->list.next = timer->list.prev = NULL;
timer_enter(timer);
spin_unlock_irq(&timerlist_lock);
fn(data);
spin_lock_irq(&timerlist_lock);
timer_exit();
goto repeat;
}
run_timer_list_running = NULL;
++timer_jiffies;
tv1.index = (tv1.index + 1) & TVR_MASK;
curr = queued.next;
while (curr != &queued) {
struct timer_list *timer;
timer = list_entry(curr, struct timer_list, list);
curr = curr->next;
internal_add_timer(timer);
}
}
spin_unlock_irq(&timerlist_lock);
}
|
从代码中可以看到,这个函数的主体是一个while循环,而while循环中的主体是一个goto循环(repeat)。在goto循环中,有那么几句:
... timer = list_entry(curr, struct timer_list, list);
fn = timer->function;
data= timer->data;
... fn(data);
...
|
关于list_entry宏的用途,博客中“
通过结构体成员得到结构体的起始地址”一文有详细介绍。timer是一个timer_list结构,即Linux中的定时器,它的详细成分如下:
struct timer_list {
struct list_head list;
unsigned long expires;
unsigned long data;
void (*function)(unsigned long);
};
|
其中expires成员记录的是定时器的“到期”时间,function指向定时器的处理函数,data是定时器处理函数的参数。看到这里,应该可以“猜测”到run_timer_list()是干嘛用的了:扫描定时器队列,然后运行那些已经“到期”了的定时器处理函数,同时将他们从定时器队列中删除。当然,这只是一个大概的流程,还要很多细节上面的实现没有研究。
关于定时器的细节,可以另外开一个“Linux定时器分析”专题,不属于时钟中断的范畴。到此,Linux 2.4.35时钟中断的分析结束。本人水平有限,有什么写得不妥的地方,欢迎大家指出,共同讨论,共同提高!
阅读(800) | 评论(0) | 转发(0) |