linux中的jiffies变量 全局变量jiffies用来记录自系统启动以来产生的节拍的总数。启动时,内核将该变量初始化为0,此后,每次时钟中断处理程序都会增加该变量的值。一秒内时钟中断的次数等于Hz,所以jiffies一秒内增加的值也就是Hz。 系统运行时间以秒为单位,等于jiffies/Hz。 注意,jiffies类型为无符号长整型(unsigned long),其他任何类型存放它都不正确。 将以秒为单位的时间转化为jiffies: seconds * Hz 将jiffies转化为以秒为单位的时间: jiffies / Hz 相比之下,内核中将秒转换为jiffies用的多些。 * jiffies的内部表示 jiffies定义于文件中: 1. /* 2. * The 64-bit value is not atomic - you MUST NOT read it 3. * without sampling the sequence number in xtime_lock. 4. * get_jiffies_64() will do this for you as appropriate. 5. */ 6. extern u64 __jiffy_data jiffies_64; 7. extern unsigned long volatile __jiffy_data jiffies; ld(1)脚本用于连接主内核映像(在x86上位于arch/i386/kernel/vmlinux.lds.S中),然后用jiffies_64变量的初值覆盖jiffies变量。因此jiffies取整个jiffies_64变量的低32位。 访问jiffies的代码只会读取jiffies_64的低32位,通过get_jiffies_64()函数就可以读取整个64位的值。在64位体系结构上,jiffies_64和jiffies指的是同一个变量。 1. #if (BITS_PER_LONG < 64) 2. u64 get_jiffies_64(void); 3. #else 4. static inline u64 get_jiffies_64(void) 5. { 6. return (u64)jiffies; 7. } 8. #endif 1. 在中 2. #if (BITS_PER_LONG < 64) 3. u64 get_jiffies_64(void) 4. { 5. unsigned long seq; 6. u64 ret; 7. 8. do { 9. seq = read_seqbegin(&xtime_lock); 10. ret = jiffies_64; 11. } while (read_seqretry(&xtime_lock, seq)); 12. return ret; 13. } * jiffies的回绕wrap around 当jiffies的值超过它的最大存放范围后就会发生溢出。对于32位无符号长整型,最大取值为(2^32)-1,即429496795。如果节拍计数达到了最大值后还要继续增加,它的值就会回绕到0。 内核提供了四个宏来帮助比较节拍计数,它们能正确的处理节拍计数回绕的问题: 1. /* 2. * These inlines deal with timer wrapping correctly. You are 3. * strongly encouraged to use them 4. * 1. Because people otherwise forget 5. * 2. Because if the timer wrap changes in future you won't have to 6. * alter your driver code. 7. * 8. * time_after(a,b) returns true if the time a is after time b. 9. * 10. * Do this with "<0" and ">=0" to only test the sign of the result. A 11. * good compiler would generate better code (and a really good compiler 12. * wouldn't care). Gcc is currently neither. 13. */ 14. #define time_after(a,b) / 15. (typecheck(unsigned long, a) && / 16. typecheck(unsigned long, b) && / 17. ((long)(b) - (long)(a) < 0)) 18. #define time_before(a,b) time_after(b,a) 19. 20. #define time_after_eq(a,b) / 21. (typecheck(unsigned long, a) && / 22. typecheck(unsigned long, b) && / 23. ((long)(a) - (long)(b) >= 0)) 24. #define time_before_eq(a,b) time_after_eq(b,a) 25. 26. /* Same as above, but does so with platform independent 64bit types. 27. * These must be used when utilizing jiffies_64 (i.e. return value of 28. * get_jiffies_64() */ 29. #define time_after64(a,b) / 30. (typecheck(__u64, a) && / 31. typecheck(__u64, b) && / 32. ((__s64)(b) - (__s64)(a) < 0)) 33. #define time_before64(a,b) time_after64(b,a) 34. 35. #define time_after_eq64(a,b) / 36. (typecheck(__u64, a) && / 37. typecheck(__u64, b) && / 38. ((__s64)(a) - (__s64)(b) >= 0)) 39. #define time_before_eq64(a,b) time_after_eq64(b,a) * 用户空间和HZ 问题提出: 在2.6以前的内核中,如果改变内核中的HZ值会给用户空间中某些程序造成异常结果。因为内核是以节拍数/秒的形式给用户空间导出这个值的,应用程序便依赖这个特定的HZ值。如果在内核中改变了HZ的定义值,就打破了用户空间的常量关系---用户空间并不知道新的HZ值。 解决方法: 内核更改所有导出的jiffies值。内核定义了USER_HZ来代表用户空间看到的HZ值。在x86体系结构上,由于HZ值原来一直是100,所以 USER_HZ值就定义为100。内核可以使用宏jiffies_to_clock_t()将一个有HZ表示的节拍计数转换为一个由USER_HZ表示的节拍计数。 1. 在中 2. /* 3. * Convert jiffies/jiffies_64 to clock_t and back. 4. */ 5. clock_t jiffies_to_clock_t(long x) 6. { 7. #if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0 8. return x / (HZ / USER_HZ); 9. #else 10. u64 tmp = (u64)x * TICK_NSEC; 11. do_div(tmp, (NSEC_PER_SEC / USER_HZ)); 12. return (long)tmp; 13. #endif 14. } 15. 16. unsigned long clock_t_to_jiffies(unsigned long x) 17. { 18. #if (HZ % USER_HZ)==0 19. if (x >= ~0UL / (HZ / USER_HZ)) 20. return ~0UL; 21. return x * (HZ / USER_HZ); 22. #else 23. u64 jif; 24. 25. /* Don't worry about loss of precision here .. */ 26. if (x >= ~0UL / HZ * USER_HZ) 27. return ~0UL; 28. 29. /* .. but do try to contain it here */ 30. jif = x * (u64) HZ; 31. do_div(jif, USER_HZ); 32. return jif; 33. #endif 34. } 35. u64 jiffies_64_to_clock_t(u64 x) 36. { 37. #if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0 38. do_div(x, HZ / USER_HZ); 39. #else 40. /* 41. * There are better ways that don't overflow early, 42. * but even this doesn't overflow in hundreds of years 43. * in 64 bits, so.. 44. */ 45. x *= TICK_NSEC; 46. do_div(x, (NSEC_PER_SEC / USER_HZ)); 47. #endif 48. return x; 49. } 50. 1. 在中 2. /* 3. * do_div() is NOT a C function. It wants to return 4. * two values (the quotient and the remainder), but 5. * since that doesn't work very well in C, what it 6. * does is: 7. * 8. * - modifies the 64-bit dividend _in_place_ 9. * - returns the 32-bit remainder 10. * 11. * This ends up being the most efficient "calling 12. * convention" on x86. 13. */ 14. #define do_div(n,base) ({ / 15. unsigned long __upper, __low, __high, __mod, __base; / 16. __base = (base); / 17. asm("":"=a" (__low), "=d" (__high):"A" (n)); / 18. __upper = __high; / 19. if (__high) { / 20. __upper = __high % (__base); / 21. __high = __high / (__base); / 22. } / 23. asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (__base), "0" (__low), "1" (__upper)); / 24. asm("":"=A" (n):"a" (__low),"d" (__high)); / 25. __mod; / 26. }) 用户空间期望HZ=USER_HZ,但是如果它们不相等,则由宏完成转换。 http://www.cnblogs.com/simonshi/archive/2010/12/13/1694819.html
linux中的jiffies变量
最新推荐文章于 2022-12-07 23:05:45 发布