在 Linux 操作系统中,很多活动都和时间有关,例如:进程调度和网络处理等等。所以说,了解 Linux 操作系统中的时钟处理机制有助于更好地了解 Linux 操作系统的运作方式。本文分析了 Linux 2.6.25 内核的时钟处理机制,首先介绍了在计算机系统中的一些硬件计时器,然后重点介绍了 Linux 操作系统中的硬件时钟和软件时钟的处理过程以及软件时钟的应用。最后对全文进行了总结。
1 计算机系统中的计时器
在计算机系统中存在着许多硬件计时器,例如 Real Timer Clock ( RTC )、Time Stamp Counter ( TSC ) 和 Programmable Interval Timer ( PIT ) 等等。
这部分内容不是本文的中点,这里仅仅简单介绍几种,更多内容参见参考文献:
●Real Timer Clock ( RTC ):
独立于整个计算机系统(例如: CPU 和其他 chip )
内核利用其获取系统当前时间和日期
●Time Stamp Counter ( TSC ):
从 Pentium 起,提供一个寄存器 TSC,用来累计每一次外部振荡器产生的时钟信号
通过指令 rdtsc 访问这个寄存器
比起 PIT,TSC 可以提供更精确的时间测量
●Programmable Interval Timer ( PIT ):
时间测量设备
内核使用的产生时钟中断的设备,产生的时钟中断依赖于硬件的体系结构,慢的为 10 ms 一次,快的为 1 ms 一次
High Precision Event Timer ( HPET ):
PIT 和 RTC 的替代者,和之前的计时器相比,HPET 提供了更高的时钟频率(至少10 MHz )以及更宽的计数器宽度(64位)
一个 HPET 包括了一个固定频率的数值增加的计数器以及3到32个独立的计时器,这每一个计时器有包涵了一个比较器和一个寄存器(保存一个数值,表示触发中断的时机)。每一个比较器都比较计数器中的数值和寄存器中的数值,当这两个数值相等时,将产生一个中断
2 硬件时钟处理
这里所说的硬件时钟处理特指的是硬件计时器时钟中断的处理过程。
2.1 数据结构
和硬件计时器(本文又称作硬件时钟,区别于软件时钟)相关的数据结构主要有两个:
struct clocksource :对硬件设备的抽象,描述时钟源信息
struct clock_event_device :时钟的事件信息,包括当硬件时钟中断发生时要执行那些操作(实际上保存了相应函数的指针)。本文将该结构称作为“时钟事件设备”。
上述两个结构内核源代码中有较详细的注解,分别位于文件 clocksource.h 和 clockchips.h 中。需要特别注意的是结构 clock_event_device 的成员 event_handler ,它指定了当硬件时钟中断发生时,内核应该执行那些操作,也就是真正的时钟中断处理函数。 在2.3节“时钟初始化”部分会介绍它真正指向哪个函数。
Linux 内核维护了两个链表,分别存储了系统中所有时钟源的信息和时钟事件设备的信息。这两个链表的表头在内核中分别是 clocksource_list 和 clockevent_devices 。图2-1显示了这两个链表。
图2-1 时钟源链表和时钟事件链表
![](http://it.kswchina.com/UploadFiles_9545/200809/20080916083616251.gif)
2.2 通知链技术( notification chain )
在时钟处理这部分中,内核用到了所谓的“通知链( notification chain )”技术。所以在介绍时钟处理过程之前先来了解下“通知链”技术。
在 Linux 内核中,各个子系统之间有很强的相互关系,一些被一个子系统生成或者被探测到的事件,很可能是另一个或者多个子系统感兴趣的,也就是说这个事件的获取者必须能够通知所有对该事件感兴趣的子系统,并且还需要这种通知机制具有一定的通用性。基于这些, Linux 内核引入了“通知链”技术。
2.2.1 数据结构:
通知链有四种类型,
1原子通知链( Atomic notifier chains ):通知链元素的回调函数(当事件发生时要执行的函数)只能在中断上下文中运行,不允许阻塞
2可阻塞通知链( Blocking notifier chains ):通知链元素的回调函数在进程上下文中运行,允许阻塞
3原始通知链( Raw notifier chains ):对通知链元素的回调函数没有任何限制,所有锁和保护机制都由调用者维护
4SRCU 通知链( SRCU notifier chains ):可阻塞通知链的一种变体
所以对应了四种通知链头结构:
●struct atomic_notifier_head :原子通知链的链头
●struct blocking_notifier_head :可阻塞通知链的链头
●struct raw_notifier_head :原始通知链的链头
●struct srcu_notifier_head : SRCU 通知链的链头
通知链元素的类型:
struct notifier_block :通知链中的元素,记录了当发出通知时,应该执行的操作(即回调函数)
链头中保存着指向元素链表的指针。通知链元素结构则保存着回调函数的类型以及优先级,参见 notifier.h 文件。