Linux内核时钟中断设施
linux的时钟中断须要两个全局变量,分别是xtime与jiffies。
1、xtime
一个timeval结构类型变量,是从cmos电路中取得的时间,通常是从某一历史时刻开始到现今的时间,也就是为了取得我们操作系统上显示的日期。这个就是“实时时钟”,它的精确度是毫秒。获取方法是通过sys/time.h头文件上面的gettimeofday函数获取。
2、HZ
Linux核心每隔固定周期会发出timerinterrupt(IRQ0),HZ是拿来保存每1秒有几次timerinterrupts。如HZ为1000,代表每秒有1000次timerinterrupts。HZ可在编译核心时设定,可设定100、250、300或1000。核心版本预设值为250。
HZ这个值可以理解为操作系统的时钟频度,这个时钟的精度远高于硬件的时钟频度。如HZ设置为250,这么为一秒钟250次,每次为4ms,因而操作系统的时钟精度只能达到4ms。
3、Tick
Tick是HZ的倒数linux命令详解词典,意即timerinterrupt每发生一次中断的时间。如HZ为250时,tick为4微秒(millisecond)。
4、Jiffies
在,定义了Jiffies(unsignedlong),在linux内核中jiffies远比xtime重要。每发生一次timerinterrupt,Jiffies变数会被加一。1秒内时钟中断的次数等于HZlinux内核 定时器,所以jiffies1秒内降低的值也就是HZ。
在Linux2.6中,系统时钟每1微秒中断一次(时钟频度,用HZ宏表示,定义为1000,即每秒中断1000次,2.4中定义为100,好多应用程序也一直延用100的时钟频度),这个时间单位称为一个jiffie。jiffies与绝对时间之间的转换,用两个宏来完成两种时间单位的互换:JIFFIES_TO_NS()、NS_TO_JIFFIES()。
jiffies是记录着从笔记本开机到现今总共的时钟中断次数。在linux内核中jiffies远比xtime重要,这么他取决于系统的频度,单位是Hz。
这是硬件给内核提供一个系统定时器用以估算和管理时间,连续累加一年四个多月后都会溢出(假设HZ=100,1个jiffies等于1/100秒,jiffies可记录的最大秒数为(2^32-1)/100=42949672.95秒,约合497天或1.38年),即当取值抵达最大值时继续加1,就变为了0。
因而为避免溢出须要使用这种宏函数进行:time_before()、time_after()、time_after_eq()、time_before_eq()。由于jiffies随时钟滴答变化,不能用编译器优化它,应取volatile值。
另外,80×86构架定义一个与jiffies相关的变数jiffies_64,w为64位linux内核,要等到此变数溢位可能要好几百万年。jiffies被对应至jiffies_64最低的32位元。为此,经由jiffies_64可以完全不理会溢位的问题便能取得jiffies。
5、RTC
不仅系统定时器外,还有一个与时间有关的时钟:实时时钟(RTC),这是一个硬件时钟,拿来持久储存系统时间,系统关掉后靠显卡上的微型电瓶保持计时。系统启动时,内核通过读取RTC来初始化WallTime,并存置于xtime变量中,这是RTC最主要的作用。
延后函数问题
1、sleep
Linux下的精度为秒,是精确的,实现原理如下:
注册一个讯号signal(SIGALRM,handler)。接收内核给出的一个讯号。调用alarm()函数。pause()挂起进程。
alarm是当前进程的私有定时闹铃,pause函数挂起当前进程,内核切换到其他进程运行。当alarm设置的时间到时,内核通过SIGALRM讯号去处理,pause函数返回后进程继续执行。
2、usleep
精度为微妙,但实际并不能精确到微妙。通过上面给出的操作系统时钟基础设置,系统精度由HZ系统时钟频度决定,通常设置为250时精度只能到4ms,因而usleep的微妙延后只能是起码延后的时间,时间上操作系统进行内核到用户的切换都会花10-30ms级别的时间,因而短时间的延后通常就会小于设定值。
另外usleep有以下的问题
在一些平台下不是线程安全,如HP-UX以及Linuxusleep()会影响讯号;在好多平台,如HP-UX以及个别Linux下,参数的值必须大于1*1000*1000也就是一秒linux内核 定时器,否则该函数会报错,而且立刻返回。大部份平台的帮助文档早已明晰说了,该函数是早已被放弃的函数。
3、高精度延后nanosleep、select
针对Linux平台下的高精度延后,Linux2.0.x新增了nanosleep系统调用。精度似乎可以设置到毫秒,并且仍然没有精确到毫秒,不过对于微秒级别的延后的精度早已足够高了,可以完全满足usleep难以达到的精度。但使用nanosleep应注意判定返回值和错误代码,否则容易引起cpu占用率100%。另外,nanosleep()没有usleep函数的缺点,在Solaris的多线程环境下编译器会手动把usleep()联接成nanosleep()。