日期:2014-05-16  浏览次数:20669 次

(转)Linux时钟变慢?关中断会关闭系统时钟中断?

转自:http://hi.baidu.com/deep_pro/blog/item/2d6ea0d997f601e538012ff1.html

?

听说有人抱怨他的Linux服务器或者嵌入式Linux开发板上的时间越来越慢,当时念头一闪,没有多在意
今天顿悟,果然是有道理的

用户空间的延时和定时器,都是靠内核定时器实现的。内核定时器 struct timer_list 以及相关内核api,
init_timer()、add_timer、mod_timer 、del_timer,都依赖于jiffes
一个系统时钟中断,jiffes就加1,每秒将产生 1*HZ 个jiffes
可以说,这个jiffes,也可称为滴答,等于是OS的心跳,靠着这个稳定长期的中断,内核才能够及时从一个时间片到期的进程手中夺回cpu的使用权,进行下一次调度。当然,每一次中断结束或者返回用户空间都可能进入调度,所以这里用词是及时。
2.6.21版本开始支持无滴答内核,据说能够节能。不过我想没有了滴答,内核定时器失效,很多软件怕是要重写了,所以大家都不大关注这个。

常见的计算机系统会带有一个RTC,这个才是可靠的墙上时钟源。
不过访问rtc的速度比较慢,所以只是上电的时候,内核读取一次rtc时间,之后在OS里看到的时间都是靠一个一个jiffes加上去的。

很多时候,为了保护临界资源,不得不关闭所有中断,这个在中断处理函数中尤为常见。那么就有可能在关闭中断后的临界区,发生了系统时钟中断,这次时 钟中断就被忽略了。导致jiffies没有增加,进而影响系统时钟精度。这个概率我只能定性的分析。比如arm上HZ为100,pc上为1000,那么每 隔10ms或者1ms就能有一次时钟中断。而10ms期间,200MHZ的arm芯片大约能执行 0.5M 条指令,正好落在临界区的几百条指令的概率不是很大。但是计算机跑起来微小的误差也是很容易积累的,所以如有必要,可以另开一个守护进程,定时读取rtc 来修正系统时间。

手工验证一下
spinlock_t lock;
unsigned long flags;

static int test_timer_init_module(void)
{
spin_lock_init(&lock);
printk( KERN_DEBUG "Module test_timer init\n" );
spin_lock_irqsave(&lock, flags);
printk( KERN_DEBUG "the jiffies is %ld\n" ,jiffies);
mdelay(2000);
printk( KERN_DEBUG "the jiffies is %ld\n" ,jiffies);
spin_unlock_irqrestore(&lock, flags);
return 0;
}

不加黑色代码,两个jiffes相差 20xx??? ,pc上HZ为1000,这个结果还是正常的
加上黑色代码,关闭中断2000ms,两个jiffes没有差别

所以写驱动一定要自律,关闭中断后的代码一定要尽可能的简洁迅速