zoukankan      html  css  js  c++  java
  • linux中的jiffies变量

    全局变量jiffies用来记录自系统启动以来产生的节拍的总数。启动时,内核将该变量初始化为0,此后,每次时钟中断处理程序都会增加该变量的值。一秒内时钟中断的次数等于Hz,所以jiffies一秒内增加的值也就是Hz。

       系统运行时间以秒为单位,等于jiffies/Hz。

    注意,jiffies类型为无符号长整型(unsigned long),其他任何类型存放它都不正确。

    将以秒为单位的时间转化为jiffies:

    seconds * Hz

    将jiffies转化为以秒为单位的时间:

    jiffies / Hz

    相比之下,内核中将秒转换为jiffies用的多些。

    • jiffies的内部表示

       jiffies定义于文件<linux\Jiffies.h>中:

    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. 在<Time.c(kernel)>中
    2. #if (BITS_PER_LONG < 64)
    3. u64 get_jiffies_64(void)
    4. {
    5.     unsigned long seq;
    6.     u64 ret;
    7. do {
    8.         seq = read_seqbegin(&xtime_lock);
    9.         ret = jiffies_64;
    10.     } while (read_seqretry(&xtime_lock, seq));
    11. return ret;
    12. }
    • 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. #define time_after_eq(a,b)  \
    20.     (typecheck(unsigned long, a) && \
    21.      typecheck(unsigned long, b) && \
    22.      ((long)(a) - (long)(b) >= 0))
    23. #define time_before_eq(a,b) time_after_eq(b,a)
    24. /* Same as above, but does so with platform independent 64bit types.
    25. * These must be used when utilizing jiffies_64 (i.e. return value of
    26. * get_jiffies_64() */
    27. #define time_after64(a,b)   \
    28.     (typecheck(__u64, a) && \
    29.      typecheck(__u64, b) && \
    30.      ((__s64)(b) - (__s64)(a) < 0))
    31. #define time_before64(a,b)  time_after64(b,a)
    32. #define time_after_eq64(a,b)    \
    33.     (typecheck(__u64, a) && \
    34.      typecheck(__u64, b) && \
    35.      ((__s64)(a) - (__s64)(b) >= 0))
    36. #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. 在<Time.c(kernel)>中
    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. unsigned long clock_t_to_jiffies(unsigned long x)
    16. {
    17. #if (HZ % USER_HZ)==0
    18. if (x >= ~0UL / (HZ / USER_HZ))
    19. return ~0UL;
    20. return x * (HZ / USER_HZ);
    21. #else
    22.     u64 jif;
    23. /* Don't worry about loss of precision here .. */
    24. if (x >= ~0UL / HZ * USER_HZ)
    25. return ~0UL;
    26. /* .. but do try to contain it here */
    27.     jif = x * (u64) HZ;
    28.     do_div(jif, USER_HZ);
    29. return jif;
    30. #endif
    31. }
    32. u64 jiffies_64_to_clock_t(u64 x)
    33. {
    34. #if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
    35.     do_div(x, HZ / USER_HZ);
    36. #else
    37. /*
    38.      * There are better ways that don't overflow early,
    39.      * but even this doesn't overflow in hundreds of years
    40.      * in 64 bits, so..
    41.      */
    42.     x *= TICK_NSEC;
    43.     do_div(x, (NSEC_PER_SEC / USER_HZ));
    44. #endif
    45. return x;
    46. }
    1. 在<Div64.h(include\asm-i385)>中
    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,但是如果它们不相等,则由宏完成转换。

  • 相关阅读:
    Ubuntu adb devices :???????????? no permissions (verify udev rules) 解决方法
    ubuntu 关闭显示器的命令
    ubuntu android studio kvm
    ubuntu 14.04版本更改文件夹背景色为草绿色
    ubuntu 创建桌面快捷方式
    Ubuntu 如何更改用户密码
    ubuntu 14.04 返回到经典桌面方法
    ubuntu 信使(iptux) 创建桌面快捷方式
    Eclipse failed to get the required ADT version number from the sdk
    Eclipse '<>' operator is not allowed for source level below 1.7
  • 原文地址:https://www.cnblogs.com/hnrainll/p/2095643.html
Copyright © 2011-2022 走看看