Linux内核时间管理(二)——jiffies与jiffies_64释疑

摘要:
Linux内核定义jiffies变量来记录从系统启动到当前时间由系统时钟生成的滴答数。其声明如下:externau64__jiffy_datajiffies_64;可以看出,jiffies变量的长度在32位系统中是32位,在64位系统中为64位。因此,Linux 2.6内核中引入了一个64位无符号整数变量jiffies _64。内核中的计时都是针对jiffies_64。jiffies-64也包含/Linux/jiffies。h中有一条语句:externau64__jiffy_datajiffies:64;其中u64是无符号长类型。这是jiffies_64变量的定义。或者干脆用jiffies_64代替jiffies?虽然,jiffies和jiffies_64是两个变量,但它们最终指向相同的地址,只是jiffies是jiffies-64变量的低位32位。

    Linux内核中定义了jiffies变量来记录从系统启动到当前时刻系统时钟所产生的tick数。jiffies变量是一个无符号整型数值,即unsigned long类型。它的声明如下(在 include/linux/jiffies.h 中):

extern u64 __jiffy_data jiffies_64;

    由此可见,jiffies变量在32位系统中的长度是32位,在64位系统中长度为64位。

    在32位系统中,HZ=1000时,jiffies只要约 49.7 天就会发生回绕(溢出),而回绕会给内核时间度量带来混乱和其他潜在的问题。因此,在Linux2.6内核中引入一个64位的无符号整型变量jiffies_64,内核中计时都是对jiffies_64进行递增。jiffies_64也在 include/linux/jiffies.h 中有声明: 

extern u64 __jiffy_data jiffies_64;

    其中,u64为unsigned long long类型。在 1000HZ 的情况下,该变量运行几亿年都不会发出回绕,从而有效防止了回绕可能引起的问题。这就是定义jiffies_64变量的原因。

    那么,既然在32位机器上也是用64位计时,为什么不直接把jiffies变量改为u64类型呢?或者说干脆用jiffies_64来代替jiffies呢?根本原因是为了保持兼容性及访问效率!从兼容性方面来看,大量的驱动程序使用jiffies 变量来进行一些与时间相关的操作,所以内核中需要保留该变量,以免影响系统功能;从访问效率方面来看,因为在 32 位的系统中访问 64 位的 jiffies_64 变量需要进行两次内存访问,一来访问速度没有直接访问 jiffies 来得快,二来无法保证原子性(在两次内存访问中间可能会被中断,从而造成读取数据的不正确)。但是当真的需要访问jiffies_64变量时(一般在驱动程序中很少访问 jiffies_64,通常只有内核核心代码才会访问),内核也提供了 get_jiffies_64() 函数来访问。该函数采用了加锁机制(xtime_lock),以防止读取数据的不正确。

    虽然,jiffies和jiffies_64是两个变量,但它们最终指向相同的地址,只是jiffies取的是jiffies_64变量的低32位。这种效果通过链接程序实现的。通过链接器(ld)脚本 vmlinux.lds (x86 上位于 arch/x86/kernel下) 可看到: 

1 OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") 
2 OUTPUT_ARCH(i386) 
3 ENTRY(phys_startup_32) 
4 jiffies = jiffies_64;

     其中最后一条语句的作用是,让符号jiffies的地址等于符号jiffies_64的地址,即让jiffies变量占用 jiffies_64 的低 32 位。这里涉及到链接器中的一个重要的概念:

在目标文件内定义的符号可以在链接器脚本内赋值,此时该符号应被定义为全局的。每个符号都对应一个地址,在链接器中的赋值(=)操作就是更改这个符号对应的地址。

    所以,这和 C 语言中的等于(=)是完全不同的概念:C 中是赋值,链接器中是改变地址。

    另外,jiffies_64 变量会被初始化为 INITIAL_JIFFIES ,该值定义在文件 include/linux/jiffies.h 中:

1 /*
2  * Have the 32 bit jiffies value wrap 5 minutes after boot
3  * so jiffies wrap bugs show up earlier.
4  */
5 #define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ))

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

 

 

参考文献:

【1】:http://www.groad.net/bbs/thread-3352-1-1.html

【2】:http://bbs.csdn.net/topics/320154818

【3】:《Linux内核设计与实现(原书第3版)》第11章

免责声明:文章转载自《Linux内核时间管理(二)——jiffies与jiffies_64释疑》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇[转]找到运行的Ubuntu版本对应的内核源码group by 两个或以上条件的分析下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Linux下备份系统至另一硬盘

首先会想到dd命令. 但,, 1,若是小硬盘还好,上T的大硬盘这样做肯定不明智; 2,况且dd是在硬件层面的拷贝,前面的MBR也会随之恢复到另一个盘,若源硬盘是100G,目标盘是200G,又会出问题,200G的硬盘由于被覆盖写入了100G硬盘的MBR导致只可用100G,更何况重写MBR相当的麻烦; 所以最好不要用类似 dd if=/dev/sda of=/...

VBS基本知识

由于一些需要,开始学习VBS了。此篇文章一直将处于编辑添加状态。 1、VBS简介      VBS 即VBScript(Microsoft Visual Basic Script Editon),是微软开发的一套脚本语言。其详细介绍,网上可以找到很多资料。直接开始学习语言的各种特性吧。 2、VBS的编辑工具。      可以直接使用电脑自带的记事本。编辑完...

Android.mk文件官方使用说明

本页介绍了 ndk-build 所使用的 Android.mk 编译文件的语法。 概览 Android.mk 文件位于项目 jni/ 目录的子目录中,用于向编译系统描述源文件和共享库。它实际上是编译系统解析一次或多次的微小 GNU makefile 片段。Android.mk 文件用于定义 Application.mk、编译系统和环境变量所未定义的项目范...

Shell 变量

Shell 变量 定义变量时,变量名不加美元符号($,PHP语言中变量需要),如: your_name="runoob.com" 注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则: 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。 中间不能有空格,可以使用下划线(_)。 不能使用标点符号...

MATLAB的基本元素

MALTAB程序的基本数据单元是数组,MATLAB 的变量名必须以字母开头,后面可以跟字母,数字和下划线(_).只有前31个字符是有效的;如果超过了31 个字符,基余的字符将被忽略。如果声明两个变量,两变量名只有第32 个字符不同,那么MATLAB 将它们当作同一变量对待。要注意的是:确保你所声明的变量名前31 个字符是独一无二的。否则,MATLAB 将无...

Linux安装TeamViewer

  1、下载teamview centos版本 官网只有rpm版本,附件中即为官网下载的teamview最新版本 (下载tar包方式,我这里打不开teamviewer的界面,所以这里不推荐)  官方下载地址:  https://www.teamviewer.com/zhCN/download/linux/ 2、下载rpm版本后,cd切换到下载目录下,执行...