曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 8812|回复: 0
打印 上一主题 下一主题

jiffies 和 jiffies_64 的区别

[复制链接]

4917

主题

5879

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34382
跳转到指定楼层
楼主
发表于 2011-4-9 17:49:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在 Linux 内核中,jiffies 用于记录系统自启动到当前时刻系统时钟所产生的滴答数。


每一秒系统时钟的中断次数等于 HZ 的值,比如一般的 PC 中 PC 的值定义为 1000,也就是说,一秒钟内系统要收到 1000 次的时钟中断;同样,jiffies 的值在一秒钟内增加 HZ 。


系统自启动到当前时刻为止运行了 jiffies/HZ 秒。


在 include/linux/jiffies.h 中有 jiffies 的声明:
[C++] 纯文本查看 复制代码
extern unsigned long volatile __jiffy_data jiffies;

由此可见,该变量在 32 位系统中为 32 位无符号整型;在 64 位系统中为 64 位无符号整型。如果只用 jiffies 的话,那么只要 49.7 天就会发生溢出,而溢出会给内核时间度量带来混乱和其他潜在的未知问题。


因此,2.6 内核中引入了一个 64 位的无符号整型变量 jiffies_64 。在 1000HZ 的情况下,该变量要在运行几亿年都不会发出溢出,从而有效的防治了溢出导致的潜在问题。jiffies_64 也在 include/linux/jiffies.h 中有声明:
[C++] 纯文本查看 复制代码
extern u64 __jiffy_data jiffies_64;

上面,u64 为 unsigned long long 类型。


为了保持兼容性及访问效率,内核中仍然保留了 jiffies 变量,因为大量的驱动程序使用该变量来进行一些与时间相关的操作。


通过链接器脚本 vmlinux.lds (x86 上位于 arch/x86/kernel 下) 可看到:
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(phys_startup_32)
jiffies = jiffies_64;



这里使得 jiffies 只占用了 jiffies_64 的低 32 位。这里可能会有疑问,链接器脚本如何得知这两个定义在别的文件里的变量?long long 型变量赋值给 long 型变量怎么不会发出警告?


关于上面的疑问,涉及到链接器中的一个重要的概念:
在目标文件内定义的符号可以在链接器脚本内赋值,此时该符号应试被定义为全局的。每个符号都对应了一个地址,在链接器中的复制就是更改这个符号对应的地址。所以,这和 C 语言中的赋值是完全不同的概念!C 中是赋值,链接器中是改变地址,所以不存在发出类型不相符的警告问题。


下面代码模拟这一过程:


链接代码 jiffies.lds:
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")


OUTPUT_ARCH(i386)


jiffies = jiffies_64;


用户态程序代码:


[C++] 纯文本查看 复制代码
#include <stdio.h> 


unsigned long long jiffies_64 = 0x112345678; 
unsigned long jiffies; 


int main() 
{ 
        printf ("jiffies_64 = 0x%llx\n", jiffies_64); 
        printf ("jiffies_64 = %p\n", &jiffies_64); 


        printf ("jiffies = 0x%lx\n", jiffies); 
        printf ("jiffies = %p\n", &jiffies); 
        return (0); 
} 


编译,运行,输出:
[beyes@SLinux jiffies]$ gcc -Wall -std=c99 -o jiffies jiffies.c jiffies.lds
[beyes@SLinux jiffies]$ ./jiffies
jiffies_64 = 0x112345678
jiffies_64 = 0x80496f0
jiffies = 0x12345678
jiffies = 0x80496f0


由输出可见,jiffies 的地址和 jiffies_64 是一样的,不同的是在程序中体现的长度不同罢了。到此,也可以看到,链接器对定义在目标文件中的全局变量(同名全局符号)是可见的。

另外,jiffies_64 变量会被初始化为 INITIAL_JIFFIES ,该值定义在文件 include/linux/jiffies.h 中:
[C++] 纯文本查看 复制代码
 
/*
 * Have the 32 bit jiffies value wrap 5 minutes after boot
 * so jiffies wrap bugs show up earlier.
 */
#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ))

这样,就使得系统在启动后 5 分钟时发生 jiffies 回绕。这么做有利于在早期设备驱动程序因 jiffies 回绕导致的逻辑错误,方便驱动程序的开发。

在设备驱动程序中,通常使用 jiffies 变量。因为在 32 位的系统中访问 64 位的 jiffies_64 没有直接访问 jiffies 来得快,因为在 32 位系统中访问 64 位变量需要进行两次内存访问,而且在两次内存访问中可能不是原子的,且可能会被中断,从而造成读取数据的不正确。对于需要访问 jiffies_64 变量(一般在驱动程序中很少访问 jiffies_64,通常只有内核核心代码才会访问),内核提供了 get_jiffies_64() 来访问,该函数采用了加锁机制,以防止读取数据的不正确。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-4-29 20:05 , Processed in 0.080202 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表