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,但是如果它们不相等,则由宏完成转换。

  • 相关阅读:
    代码高亮测试
    docker详解
    生成python项目的docker模板
    Windows下载Ubuntu的文件,用WinSCP软件(建议用MobeXterm),Ubuntu开启SSH连接
    分配堆内存的四种方式
    像素和rgb
    自由飞翔
    像素和分辨率的关系
    DOM事件阶段以及事件捕获与事件冒泡先后执行顺序
    有点甜 汪苏泷
  • 原文地址:https://www.cnblogs.com/hnrainll/p/2095643.html
Copyright © 2011-2022 走看看