熟悉了基本的编程方法之后,我们的兴趣就在于,计算机如何实现这一切的呢?在那些应用层 API 和底层系统硬件之间,操作系统和库函数究竟做了些什么?
首先看下 Linux 时间处理的一般过程:
图 1. 时间处理过程
应用程序部分已经在第一部分详细介绍过了,在第二部分我将介绍硬件和 GlibC 相关实现的一些概况。
硬件
PC 机里常见的时钟硬件有以下这些。
RTC (Real Time Clock,实时时钟)
人们需要知道时间的时候,可以看看钟表。计算机系统中钟表类似的硬件就是外部时钟。它依靠主板上的电池,在系统断电的情况下,也能维持时钟的准确性。计算机需要知道时间的时候,就需要读取该时钟。
在 x86 体系中,这个时钟一般被称为 Real Time Clock。RTC 是主板上的一个 ">CMOS 芯片,比如 Motorola 146818,该芯片独立于 CPU 和其他芯片,可以通过 0x70 和 0x71 端口操作 RTC。RTC 可以周期性地在 IRQ 8 上触发中断,但精度很低,从 2HZ 到 8192HZ。
以 Motorola 146818 为例,软件可以通过 I/O 指令读写以下这些值:
图 2. Motorola 146818
可以看到,RTC 能提供精确到秒的实时时间值。
TSC (Time Stamp Counter)
CPU 执行指令需要一个外部振荡器产生时钟信号,从 CLK 管脚输入。x86 提供了一个 TSC 寄存器,该寄存器的值在每次收到一个时钟信号时加一。比如 CPU 的主频为 1GHZ,则每一秒时间内,TSC 寄存器的值将增加 1G 次,或者说每一个纳秒加一次。x86 还提供了 rtdsc 指令来读取该值,因此 TSC 也可以作为时钟设备。TSC 提供了比 RTC 更高精度的时间,即纳秒级的时间精度。
PIT (Programmable Interval Timer)
PIT 是 Programmable Interval Timer 的缩写,该11585.html">硬件设备能定时产生中断。早期的 PIT 设备是 8254,现在多数可以集成在 Intel 的 I/O Control Hub 电路中,可以通过端口 0x40~0x43 访问 PIT。系统利用 PIT 来产生周期性的时钟中断,时钟中断通过 8259A 的 IRQ0 向 CPU 报告。它的精度不高,其入口 clock 的频率为 1MHz,理论上能产生的最高时钟频率略小于 0.5MHz。实际系统往往使用 100 或者 1000Hz 的 PIT。
HPET (High Precision Event Timer)
PIT 的精度较低,HPET 被设计来替代 PIT 提供高精度时钟中断(至少 10MHz)。它是由微软和 Intel 17872.html">联合开发的。一个 HPET 包括了一个固定频率的数值增加的计数器以及 3 到 32 个独立的计时器,这每一个计时器有包涵了一个比较器和一个寄存器(保存一个数值,表示触发中断的时机)。每一个比较器都比较计数器中的数值和寄存器中的数值,当这两个数值相等时,将产生一个中断。