linux jiffies的比较
jiffies的定义:
// include/linux/jiffies.h extern u64 __jiffy_data jiffies_64; extern unsigned long volatile __jiffy_data jiffies;
Gcc defines __ARMEB__ for big-endian ARM and __ARMEL__ for little-endian ARM.
以小端为例,arch/arm/kernel/vmlinux.lds 中将jiffies定义为jiffies_64的低4位。
以arm平台为例,jiffies变量是unsigned long类型的,那么最大为0xffffffff=4294967295L, 若HZ为100,
则4294967295L/100/60/60/24=497,大约在497天后jiffies会溢出。kernel里为了比较两个时间戳的先后提供了几个宏,
这几个宏在溢出时仍然能得到正确的结果:
// include/linux/jiffies.h #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):
1. a = 2, b = 1
b - a = 1 - 2 = 1 + (0xffff,fffe) = 0xffff,ffff = -1 < 0, 所以 timer_after(a,b) 返回真(1)
2. a = 1, b = 2
b - a = 2 - 1 = 2 + (0xffff,ffff) = 0x0000,0001 > 0 , 所以 timer_after(a,b) 返回假(0)
3. a = 1, b = 0x8000,0000
b - a = 0x8000,0000 - 1 = 0x7fff,ffff > 0, => timer_after(a,b) 返回假(0)
4. a = 1, b = 0x8000,0001
b - a = 0x8000,0001 - 1 = 0x8000,0000 < 0, => timer_after(a,b) 返回真(1)
5. a = 1, b = 0xffff,ffff
b - a = 0xffff,ffff - 1 = 0xffff,ffff + 0xffff,ffff = 0xffff,fffe = -1 < 0, => timer_after(a,b) 返回真(1)
由上3,4,5可见timer_after(a,b)仍然有一定局限定,相比较的两个时间戳在逻辑上相差时间不大于MAX_ULONG/2(0x7fff,ffff). 如果相差大于此值则比较结果就是错的。
Basically it assumes that the two values you are comparing will never be more than MAX_ULONG/2 apart. Which for jiffies means 270 some odd days on 32-bit platforms.
好在我们通常使用jiffies和相关宏的使用场景都相对单一,时间跨度不可能这么大。所以一般直接使用没什么问题。