linux定时器和Jiffies

合集下载
相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

1.linux HZ

Linux核心几个重要跟时间有关的名词或变数,以下将介绍HZ、tick与jiffies。

HZ

Linux核心每隔固定周期会发出timer interrupt (IRQ 0),HZ是用来定义每一秒有几次timer interrupts。举例来说,HZ为1000,代表每秒有1000次timer interrupts。 HZ可在编译核心时设定,如下所示(以核心版本2.6.20-15为例):

adrian@adrian-desktop:~$ cd /usr/src/linux

adrian@adrian-desktop:/usr/src/linux$ make menuconfig

Processor type and features ---> Timer frequency (250 HZ) --->

其中HZ可设定100、250、300或1000。

小实验

观察/proc/interrupt的timer中断次数,并于一秒后再次观察其值。理论上,两者应该相差250左右。

adrian@adrian-desktop:~$ cat /proc/interrupts | grep timer && sleep 1 && cat /proc/interrupts | grep timer

0: 9309306 IO-APIC-edge timer

0: 9309562 IO-APIC-edge timer

上面四个栏位分别为中断号码、CPU中断次数、PIC与装置名称。

要检查系统上HZ的值是什么,就执行命令

cat kernel/.config | grep '^CONFIG_HZ='

2.Tick

Tick是HZ的倒数,意即timer interrupt每发生一次中断的时间。如HZ为250时,tick为4毫秒(millisecond)。

3.Jiffies

Jiffies为Linux核心变数(unsigned long),它被用来记录系统自开机以来,已经过了多少tick。每发生一次timer interrupt,Jiffies变数会被加一。值得注意的是,Jiffies于系统开机时,并非初始化成零,而是被设为-300*HZ (arch/i386/kernel/time.c),即代表系统于开机五分钟后,jiffies 便会溢位。那溢位怎么办?事实上,Linux核心定义几个macro(timer_after、time_after_eq、time_before与time_before_eq),即便是溢位,也能借由这几个macro正确地取得jiffies的内容。

另外,80x86架构定义一个与jiffies相关的变数jiffies_64 ,此变数64位元,要等到此变数溢位可能要好几百万年。因此要等到溢位这刻发生应该很难吧。

3.1 jiffies及其溢出

全局变量jiffies取值为自操作系统启动以来的时钟滴答的数目,在头文件中定义,数据类型为unsigned long volatile (32位无符号长整型)。

jiffies转换为秒可采用公式:(jiffies/HZ)计算,

将秒转换为jiffies可采用公式:(seconds*HZ)计算。

当时钟中断发生时,jiffies 值就加1。因此连续累加一年又四个多月后就会溢出(假定HZ=100,1个jiffies等于1/100秒,jiffies可记录的最大秒数为 (2^32 -1)/100=42949672.95秒,约合497天或1.38年),即当取值到达最大值时继续加1,就变为了0。

3.4 Linux内核如何来防止jiffies溢出

Linux内核中提供了以下四个宏,可有效解决由于jiffies溢出而造成程序逻辑出错的情况。下面是从Linux Kernel 2.6.7版本中摘取出来的代码:/*

* These inlines deal with timer wrapping correctly. You are

* strongly encouraged to use them

* 1. Because people otherwise forget

* 2. Because if the timer wrap changes in future you won't have to * alter your driver code.

*

* time_after(a,b) returns true if the time a is after time b.

*

* Do this with "<0" and ">=0" to only test the sign of the result. A * good compiler would generate better code (and a really good compiler * wouldn't care). Gcc is currently neither.

*/

#define time_after(a,b) \

(typecheck(unsigned long, a) && \

typecheck(unsigned long, b) && \

((long)(b) - (long)(a) < 0))

#define time_before(a,b) time_after(b,a)

#define time_after_eq(a,b) \

(typecheck(unsigned long, a) && \

typecheck(unsigned long, b) && \

((long)(a) - (long)(b) >= 0))

#define time_before_eq(a,b) time_after_eq(b,a)

在宏time_after中,首先确保两个输入参数a和b的数据类型为unsigned long,然后才执行实际的比较。

8. 结论

系统中采用jiffies来计算时间,但由于jiffies溢出可能造成时间比较的错误,因而强烈建议在编码中使用 time_after等宏来比较时间先后关系,这些宏可以放心使用。

内核时钟:

内核使用硬件提供的不同时钟来提供依赖于时间的服务,如

相关文档
最新文档