对 jiffies 溢出、回绕及 time_after 宏的理解

小默原创,转载请保留原文链接:http://blog.csdn.net/wshjldaxiong/article/details/8439518

最近在慢慢的啃着 Linux 内核的相关源码,读到 jiffies 这里,这个东西和 windows 下 GetTickCount 获得的值是类似的,就是系统启动以来所经历的 tick 数(windows 下是一毫秒一 tick),神马 timeout、delay、sleep 之类的东西还有进程的调度等,凡是与时间有关的东西大多依赖于它。以前看书的时候总是读到类似这样的内容:这个值一般是32位的,会在0到2^32之间循环,约49.71天。

那时还很天真的想,自己一般一天关机一次,想来是够用了,现在再看,够用个毛啊,一年到头不关机的机器多的是啊。想来那些写操作系统的大牛是不会留下这么二的 BUG 的,果然,今天研究到了这里,在 Linux 内核中使用了一个这样的宏来解决这个问题:

[cpp]  view plain copy
  1. #define time_after(a,b)\  
  2. (typecheck(unsigned long,a) &&\  
  3. typecheck(unsigned long,b) &&\  
  4. ((long)(b)-(long)(a)<0) //当 a 在 b 的后面(大于等于),此宏为真  

将无符号数转成有符号数计算,的确是可以解决自加溢出的问题,以 char 为例,unsigned char 的 255 比 0 大,但是转成 signed char 之后其值为 -1 比 0 小,于是 -1, 0, 1 ... 就形成了连续性的递增关系,解决了溢出时的问题(这里不明白的同学请随便找一本C语言书看看补码、反码那一块)。

结合程序来看,假设我需要设置一个 5 tick 的延时,那么 timeout = jiffies + 5;如果运气不好,恰巧这个时候 jiffies 等于254,那么 timeout  等于 254 + 5 = 3,若没有使用宏而直接判断 jiffies > timeout ,那么结果就不对了,本来在 5 个 tick 内 jiffies 都应该小于 timeout 才对的,但 254 直接就大于 3,于是延时失败了。而使用宏的话 254 当做 -2 ,于是 5 个 tick 过后它才会大于 3,符合预期。

但我写到这里,上面的内容基本上等同于废话 ^@^ ,因为那些并不是我读到这个部分源码时所纠结的问题,我纠结的是,当 jiffies 从 127 加到 128 ,由正数转为负数的回绕产生时,time_after 是如何保证比较的结果的正确性的?为此,我自己写了个简化版的宏来做试验:

[cpp]  view plain copy
  1. #define time_after(a,b) ((char)(b)-(char)(a)<0)   
  2. //这个宏在 VC 下是不对的,后面解释  


经过一番研究以及阅读别人的帖子,我终于了解了它的原理,在此与大家分享,希望能够对他人有所帮助。

我们假设当前的 jiffies 值为 127 其 5 个 tick 之后的值为 132 ,以有符号来解释该数据则 timeout = -124,那么 jiffies 如何可能会小于 timeout 呢?timeout - jiffies > 0 又是怎么成立的呢?请听下回分解!

别砸显示器,开个玩笑。-124 - 127 = -251 是负数,貌似条件无法成立了,但它就能成立,因为 -251 在内存里的存储是 0xFF05,它超出了一个 byte 的范围,于是将其高位截去剩下 0x05,它是正数,于是 timeout - jiffies > 0 就成立了,坑爹啊!!!

但这个写法有一个小小的缺点,就是延时 tick 不能大于 127,否则计算就不正确了,换成 32 位的情况就是延时 tick 不能大于 2^31-1 想来也没有哪个程序会一次性 delay 25 天吧,所以这一套宏便能够胜任了。

顺便一提,我比较倒霉,因为我是在 VC 的环境下测试的这个宏,结果怎么都不对,原因是在于其运算时隐式转换的规则有细微的不同,它得出结果后并没有将数据截去高位,而是应该升级成了 int 型,于是负号被保留了下来,判断出错。改为如下即可:

[cpp]  view plain copy
  1. #define time_after(a,b) ((char)((char)(b)-(char)(a))<0)  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值