6.1.2 系统时钟
操作系统应该具备在将来某个时刻调度某个任务的能力,所以需要一种能保证任务准时调度运行的机制。该机制的核心就是系统时钟。与实时钟RTC不同,系统时钟是定时器硬件和系统软件的结合。
1.系统时钟中断源
系统时钟硬件在通过编程配置后可以产生一定频率的中断。在个人计算机中,与该中断相关的中断向量号是0。系统软件通过累计从开机到现在产生该中断的次数来维护系统时间,形成系统时钟。本小节主要介绍在个人计算机中常见的、可以用于系统时钟的硬件定时器。
(1)8254可编程定时器。
当 前使用最普遍的定时器硬件芯片是Intel 8254可编程定时器芯片(Programable Interval Timer,简称为PIT),该芯片由一个1 193 181Hz的振荡器驱动,含有3个独立的通道;每个通道包含一个16位的计数器。对于每一个到达的时钟脉冲,通道中计数器中的值减1,当计数器减到0时, 相应的通道就会产生一次输出。其中通道0的输出连接到了中断控制器,其对应的中断向量号为0,用于产生系统时钟所需要的滴答;通道1的输出在早期的计算机 中用于DRAM的刷新,新近的计算机系统中有专门的硬件负责DRAM的刷新,通道1的功能已经不存在了;通道2的输出连接到了位于主板上的蜂鸣器(PC Speaker),控制蜂鸣器发出一定频率的声音。
这里介绍一下驱动8254工作时钟频率的来历。最初的个人电脑设计时出于成本上的考虑, 主板上采用了当时广泛用于电视机且价格最便宜的一个14.318 18MHz振荡器,该振荡器的频率远远高于系统其他器件所要求的工作频率。设计师采用了3分频后得到4.77MHz驱动中央处理器8088;采用4分频后 得到3.58MHz信号用于驱动彩色图形适配器;最后将系统各种频率的基频1.193 181 6MHz(各种频率的最大公约数,即12分频)信号用做系统可编程定时器芯片的输入时钟。为了保持兼容性,可编程定时器8254一直采用这个频率的时钟作 为输入。
(2)高精度事件定时器。
高精度事件定时器(High Precision Event Timers)被设计用于取代8254可编程定时器的全部功能和实时钟RTC芯片的周期性中断功能,和8254可编程定时器相比,该定时器能产生更高精度 的周期性中断;和实时钟RTC芯片的周期性中断相比,该定时器能提供更高精度、更宽范围的中断频率。
该硬件定时器遵循Intel和 Microsoft联合制定的高精度事件定时器规范。该规范中规定一个高精度事件定时器最多拥有32个定时器。通过配置后,timer 0用于取代8254可编程定时器所产生的时钟中断;timer 1作为硬件定时器取代实时钟RTC芯片的周期性中断功能;其余的timer作为硬件定时器供内核或用户进程直接使用。
(3)处理器本地时钟。
在多处理器系统中,处理器本地时钟(CPU Local Timer)用于向本地处理器发送时钟中断请求,更新本地处理器上的相对时间jiffies。
2.其他辅助时钟源
这 类辅助时钟源不具备向系统发出中断请求的功能,但有比能产生系统时钟中断的定时器硬件更高的计时精度。在系统时钟中断处理过程中,处理程序可以利用这些时 钟的值来完成高精度时间度量,如"6.6微秒级延迟"中的udelay、ndelay就使用了这类的时钟源(如时间戳计数器)完成高精度的延迟。下面介绍 常见的这类辅助时钟源。
(1)时间戳计数器。
从Pentium开始,所有的Intel处 理器都包含一个64位的寄存器,该寄存器被称为时间戳记数器(Time Stamp Counter,简称为TSC)。TSC在CPU的每个时钟信号到来一次时加1,实际上该寄存器是一个不断增加的计数器,如果处理器的主频为1GHz,那 么TSC寄存器的每1ns增加1。汇编指令rdtsc可用于读取TSC的值。利用CPU的TSC,操作系统通常可以得到更为精准的时间度量。
(2)电源管理时钟。
内核中,除了使用上面的时间戳记数器作为系统时钟的辅助时钟源外,电源管理时钟(ACPI Power Management Timer)也可作为系统的辅助时钟源。这里对这些时钟源不做详细介绍。
3.与系统时钟相关的宏定义
(1)宏定义HZ。
宏定义Hz记录了不同体系结构下,系统时钟所要求的可编程定时器产生中断的频率。在IA32体系结构下该宏定义在文件src/include/asm-i386/param.h中的第6行定义如下:
#define HZ CONFIG_HZ /* Internal kernel timer frequency */其中的CONFIG_HZ是内核配置选项,该内核配置选项有3个频率候选值依次是100Hz、1 000Hz、250Hz,分别用于要求高系统吞吐量的服务器系统、要求快速响应的个人桌面计算机系统以及兼有两种类型应用的计算机系统中。
(2)宏定义CLOCK_TICK_RATE。
宏定义CLOCK_TICK_RATE记录了不同体系结构下,驱动可编程定时器工作的输入时钟频率。在IA32体系结构下该值在文件src/include/asm-i386/timex.h中的第15行定义如下:
#define CLOCK_TICK_RATE 1193182 /* Underlying HZ */其中,数值1 193 182是8254可编程定时器的输入时钟频率。详情请参见本小节中对8254可编程定时器的分析。
(3)宏定义LATCH。
宏定义LATCH记录了上述两个宏定义的比值,用于在内核初始化过程中设置可编程定时器中计数器寄存器counter的初始值。在IA32体系结构下,该宏定义在文件src/include/ Linux/jiffies.h中第46行定义如下:
#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */