在单处理器系统上,所有与定时有关的活动都是由IRQ线0上的可编程间隔定时器产生的中断触发的。同样,在Linux中,某些活动都尽可能在中断产生后立即执行,而其余的活动延迟。
初始化阶段
在内核初始化期间,time_init()函数被调用来建立计时体系结构,它通常执行如下操作:
初始化xtime变量。利用get_cmos_time()函数从实时时钟上读取自1970年1月1日午夜以来经过的秒数。设置xtime的tv_nsec字段,这样使得即将发生的jiffies变量溢出与tv_sec字段的增加保持一致,也就是说,它将落到秒的范围内。
初始化wall_to_monotonic变量。这个变量同xtime一样是timespec类型,只不过它存放将如何加到xtime上的秒数和纳秒数,以此来获得单向的时间流。其实,外部时钟的闰秒和同步都有可能突发地改变xtime和tv_sec和tv_nsec字段,这样使用它们不再是单向递增的。正如我们将在后面的”与POSIX定时器相关的系统调用”一节看到那样,有时内核需要一个真正单向的时间源。
如果内核支持HPET,它将调用hpet_enable()函数来确认ACPI固件是否探测到了该芯片并将它的寄存器映射到了内存地址空间中。如果结果是肯定的,那么hpet_enable()将对HPET芯片的第一个定时器编程使其以每秒1000次的频率引发IRQ0处的中断。否则,如果不能获得HPET芯片,内核将使用PIT:该芯片已经被init_IRQ()函数编程,使得它以每秒1000次的频率引发IRQ0处的中断,正如前面的“可编程间隔定时器PIT”一节描述的那样。
调用select_timer()来挑选系统中可利用的最好的定时器资源,并设置cur_timer变量指向该定时器资源对应的定时器对象的地址。
调用setup_irq(0,&irq0)来创建与IRQ0相应的中断门,IRQ0引脚连接着系统时钟中断源。Irq0变量被静态定义如下:
struct irqactionirq0=(timer_interrupt,SA_INTERRUPT,0,”timer”,NULL,NULL);
从现在起,timer_interrupt()函数将会在每个节拍到来时被调用,而中断被禁止,因为IRQ0主描述符的状态字段中的SA_INTERRUPT标志被转位。
时钟中断处理程序
timer_interrupt()函数是PIT或HPET的中断服务例程,它执行以下步骤:
在xtime_lock顺序锁上产生一个write_seqlock()来保护与定时相关的内核变量。
执行cur_timer定时器对象的mark_offset方法。正如前面的”计时体系结构的数据结构”一节解释的那样,有四种可能的情况:
a.cur_timer指向timer_hpet对象;这种情况下,HPET芯片作为时钟中断源。mark_offset方法检查自上一个节拍以来是否丢失时钟中断,在这种不太可能发生的情况下,它会相应地更新jiffies_64。接着,该方法记录下HPET周期计数器的当前值。
b.cur_time指向timer_pmtmr对象;在这种情况下pit芯片作为时钟中断源,但是内核使用APIC电源管理定时器以更高的分辨度来测量时间。mark_offset方法检查自上一个节拍以来是否丢失时钟中断,如果丢失则更新jiffies_64。然后,它记录APIC电源管理定时器计数器的当前值。
c.cur_time指向timer_tsc对象;在这种情况下,PIT芯片作为时钟中断源,但是内核使用时间戳计数器以更高的分辨度来测量时间。mark_offset方法执行与上一种情况相同的操作:检查自上一个节拍以来是否丢失时钟中断,如果丢失则更新jiffies_64。然后,它记录TSC计数器的当前值。
d.cur_timer指向timer_pit对象;这种情况下,PIT芯片作为时钟中断源,除此之外没有别的定时器电路。mark_offset方法什么也不做。
调用do_timer_interrupt()函数,do_timer_interupt()函数执行以下操作:
a.使jiffies_64的值增加1。注意,这样做是安全的,因为内核控制路径仍然为写操作保持着xtime_lock顺序锁。
b.调用update_times()函数来更新系统日期和时间,并计算当前系统负载。这些活动将在后面的”更新时间和日期”与”更新系统统计数”两节中讨论。
c.调用update_process_times()函数为本地CPU执行几个与定时相关的计数操作。
d.调用profile_tick()函数。
e.如果使用外部时钟来同步系统时钟,则每隔660秒调用一次set_rtc_mmss()函数来调整实时时钟。这个特性用来帮助网络中的系统同步它们的时钟。
调用write_sequnlock()释放xtime_lock顺序锁。
返回值1,报告中断已经被有效地处理了。