Linux设备驱动程序 之 度量时间差

概述

内核通过定时器中断来跟踪事件流;

时钟中断由系统定时硬件以及周期性的间隔产生,这个间隔由内核根据HZ的值设定,HZ是一个细节结构有关的常数;作为一般性规则,即使知道对应平台上的确切HZ值,也不应该在编程时依赖该HZ值;

如果想改变系统时钟中断发生的频率,可以通过修改HZ值来进行,但是,如果修改了头文件中的HZ值,则必须使用新的值重新编译内核以及所有模块;

每当时钟中断发生时,内核内部计数器的值增加一;这个计数器的值在系统引导值初始化为0,因此,它的值就是上次操作系统引导以来的时钟滴答数;这个计数器是一个64位变量(即使在32位架构上也是64位),称为jiffies_64;但是驱动程序发开者通常访问的是jiffies变量,它是unsigned long类型的变量,要么和jiffies_64相同,要么仅仅是jiffies_64的低23位,根据架构是64位还是32位而定;通常首选使用jiffies,因为对它的访问很快,从而对于64位jiffies_64值的访问并不需要在所有架构上都是原子的;

使用jiffies计数器

该计数器和读取计数器的工具函数包含在<linux/jiffies.h>中,但是通常只需要包含<linux/sched.h>文件,后者会自动包含jiffies.h;

需要说明的是,jiffies和jiffies_64均应该被看成只读变量;

在代码中需要记录jiffies的当前值时,可简单的访问上面说的unsigned long变量;该变量被声明为volatile,这样可以避免编译器对访问该变量的语句的优化;在代码需要计算未来的时间戳时,必须读取当前的计数器;

1 #incldue <linux/jiffies.h>
2
3 unsigned long j, stamp_1, stamp_half, stamp_n;
4
5 j = jiffies;
6
7 stamp_1 = j + HZ;
8 stamp_half = j + HZ/2;
9 stamp_n = j + n * HZ / 1000;
时间比较

只要采用正确的方式来比较不同的值,上述代码不会因为jiffies的溢出而出现问题;比较缓存时间和当前时间,应该使用下面宏:

 1 #define time_after(a,b)         2     (typecheck(unsigned long, a) &&  3      typecheck(unsigned long, b) &&  4      ((long)((b) - (a)) < 0))
 5 #define time_before(a,b)    time_after(b,a)
 6
 7 #define time_after_eq(a,b)     8     (typecheck(unsigned long, a) &&  9      typecheck(unsigned long, b) && 10      ((long)((a) - (b)) >= 0))
11 #define time_before_eq(a,b)    time_after_eq(b,a)
用户空间时间与内核时间的转换

用户空间的时间使用struct timeval和struct timespec来表示,为了在用户空间时间和内核时间之间进行转换,内核提供了下面的四个辅助函数:包含在<linux/jiffies.h>中

1 unsigned long timespec_to_jiffies(const struct timespec *value)
2 void jiffies_to_timespec(const unsigned long jiffies,
3                        struct timespec *value)
4
5 unsigned long timeval_to_jiffies(const struct timeval *value)
6 void jiffies_to_timeval(const unsigned long jiffies,
7                    struct timeval *value)
访问jiffies_64

对jiffies_64的访问不像对jiffies的访问那么直接,在64位架构上,两个变量其实是同一个变量;但是在32位架构上,对64位的访问不是原子的,必须借助一个辅助函数,该函数完成了适当的锁定:

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

原文地址:https://www.cnblogs.com/wanpengcoder/p/11760846.html

时间: 2024-11-10 21:56:46

Linux设备驱动程序 之 度量时间差的相关文章

LINUX设备驱动程序(第3版)pdf高清版免费下载

下载地址:网盘下载 备用地址:网盘下载 内容简介编辑<LINUX设备驱动程序(第3版)>已针对Linux内核的2610版本彻底更新过了.内核的这个版本针对常见任务完成了合理化设计及相应的简化,如即插即用.利用sysfs文件系统和用户空间交互,以及标准总线上的多设备管理等等.要阅读并理解本书,您不必首先成为内核黑客:只要您理解C语言并具有Unix系统调用的一些背景知识即可.您将学到如何为字符设备.块设备和网络接口编写驱动程序.为此,<LINUX设备驱动程序(第3版)>提供了完整的示例

linux设备驱动程序该添加哪些头文件以及驱动常用头文件介绍(转)

原文链接:http://blog.chinaunix.net/uid-22609852-id-3506475.html 驱动常用头文件介绍 #include <linux/***.h> 是在linux-2.6.29/include/linux下面寻找源文件.#include <asm/***.h> 是在linux-2.6.29/arch/arm/include/asm下面寻找源文件.#include <mach/***.h> 是在linux-2.6.29/arch/ar

Linux设备驱动程序学习笔记(一)

1.设备驱动程序扮演的角色:       设备程序是一个独立的“黑盒子”,使其某个特定硬件响应一个定义良好的内部编程接口,这些接口完全隐藏了设备的工作细节.用户的操作通过一组标准化的调用执行,而这些调用独立于特定的驱动程序.将这些调用映射到作用于实际硬件的设备特有操作上,则是设备驱动程序的任务.2.驱动程序的作用:        驱动程序应该处理如何使用硬件可用的问题,而将怎样使用硬件的问题留给上层应用.(提供机制,而不是策略)3.内核功能划分:        进程管理    内存管理    文

LINUX设备驱动程序笔记(一)设备驱动程序简介

<一>:设备驱动程序的作用 从一个角度看,设备驱动程序的作用在于提供机制,而不是策略.在编写驱动程序时,程序员应该特别注意下面这个基本概念:编写访问硬件的内核代码时,不要给用户强加任何特定策略.因为不同的用户有不同的需求,驱动程序应该处理如何使硬件可用的问题,而将怎样使用硬件的问题留给上层应用程序. 从另一个角度来看驱动程序,它还可以看作是应用程序和实际设备之间的一个软件层. 总的来说,驱动程序设计主要还是综合考虑下面三个方面的因素:提供给用户尽量多的选项.编写驱动程序要占用的时间以及尽量保持

LINUX设备驱动程序笔记(二)构造和运行模块

         <一>:设置测试系统 首先准备好一个内核源码树,构造一个新内核,然后安装到自己的系统中.           <二>:HelloWorld模块 #include <linux/init.h> //定义了驱动的初始化和退出相关的函数 #include <linux/module.h> //定义了内核模块相关的函数.变量及宏 MODULE_LICENSE("Dual BSD/GPL"); //该宏告诉内核,该模块采用自由许可

LINUX设备驱动程序笔记(三)字符设备驱动程序

      <一>.主设备号和次设备号        对字符设备的访问时通过文件系统内的设备名称进行的.那些设备名称简单称之为文件系统树的节点,它们通常位于/dev目录.字符设备驱动程序的设备文件可通过ls -l命令输出的第一列中的'c'来识别.块设备同样位于/dev下,由字符'b'标识 crw-rw----  1 root root    253,   0 2013-09-11 20:33 usbmon0 crw-rw----  1 root root    253,   1 2013-09

LINUX设备驱动程序笔记(四)并发和竞态

       <一>.并发及其管理 大部分竞态可通过使用内核的并发控制原语,并应用几个基本的原理来避免.第一个规则是,只要可能,就应该避免资源的共享,这种思想的明显应用就是避免使用全局变量.但硬件资源本质上就是共享的,软件资源经常需要对其他执行线程可用.全局变量并不是共享数据的唯一途径,只要我们的代码将一个指针传递给了内核的其他部分,一个新的共享就可能建立.在单个执行线程之外共享硬件或软件资源的任何时候,因为另外一个线程可能产生对该资源的不一致观察,因此必须显示地管理对该资源的访问.访问管理的

Linux 设备驱动程序 字符设备

已经无法再精简,适合入门. 1 #include<linux/module.h> 2 #include<linux/init.h> 3 4 #include<asm/uaccess.h> 5 #include <linux/types.h> 6 #include<linux/fs.h> 7 #include<linux/cdev.h> 8 struct mengc_dev{ 9 char data[64]; 10 struct cde

linux设备驱动程序注册过程详解

Linux的驱动程序注册过程,大致分为两个步骤: 模块初始化 驱动程序注册 下面以内核提供的示例代码pci-skeleton.c,详细说明一个pci设备驱动程序的注册过程.其他设备的驱动代码注册过程基本相同,大家可自行查看.使用的内核代码版本是2.6.38. 1. 模块初始化 1.1 驱动程序入口 所有的设备驱动程序都会有如下两行代码: 1922 module_init(netdrv_init_module); 1923 module_exit(netdrv_cleanup_module); m