赞
踩
目录
时间管理在内核中占有非常重要的地位。 相对于事件驱动, 内核中有大量的函数都是基于时间驱动的。内核必须管理系统的运行时间以及当前的日期和时间。
周期产生的事件都是由系统定时器驱动的。 系统定时器是一种可编程硬件芯片, 它已固定频率产生中断。 该中断就是所谓的定时器中断, 它所对应的中断处理程序负责更新系统时间, 还负责执行需要周期性运行的任务。 系统定时器和时钟中断处理程序是 Linux 系统内核管理机制中的中枢
硬件为内核提供了一个系统定时器用以计算流逝的时间, 系统定时器以某种频率自行触发时钟中断,该频率可以通过编程预定, 称节拍率。
当时钟中断发生时, 内核就通过一种特殊中断处理程序对其进行处理。 内核知道连续两次时钟中断的间隔时间。 这个间隔时间称为节拍(tick) 。内核就是靠这种已知的时钟中断来计算墙上时间和系统运行时间。
系统定时器频率是通过静态预处理定义的(HZ), 在系统启动时按照 Hz 对硬件进行设置。 体系
结构不同, HZ 的值也不同。 内核在文件 <include/asm-generic/param.h> 中定义了 HZ 的实际值, 节拍率就是 HZ, 周期为 1/HZ。 一般 ARM 体系结构的节拍率多数都等于 100。
在编译 Linux 内核的时候可以通过图形化界面设置系统节拍率, 按照如下路径打开配置界面:
-> Kernel Features
-> Timer frequency (<choice> [=y])
选中“Timer frequency”, 打开以后如下图所示:
从上图可以看出可选的系统节拍率为 100Hz、 200Hz、 250Hz、 300Hz、 500Hz 和 1000Hz, 默认情况下选择 100Hz。
设置好以后打开 Linux 内核源码根目录下的.config 文件, 在此文件中有如下图所示定义:
Linux 内核会使用 CONFIG_HZ 来设置自己的系统时钟。 打开文件include/asm-generic/param.h, 有如下内容:
- # undef HZ
- # define HZ CONFIG_HZ
- # define USER_HZ 100
- # define CLOCKS_PER_SEC (USER_HZ)
宏 HZ 就是 CONFIG_HZ,HZ=100,后面编写 Linux驱动的时候会常常用到 HZ,因为 HZ 表示一秒的节拍数,也就是频率。
高节拍率
优点:
提高系统时间精度,如果采用 100Hz 的节拍率,时间精度就是 10ms,采用1000Hz 的话时间精度就是 1ms。能够以更高的精度运行,时间测量也更加准确。
缺点:
高节拍率会导致中断的产生更加频繁,频繁的中断会加剧系统的负担, 1000Hz 和 100Hz
的系统节拍率相比,系统要花费 10 倍的精力去处理中断。中断服务函数占用处理器的时间
增加,需要根据实际情况,选择合适的系统节拍率。
全局变量 jiffies 用来记录自系统启动以来产生的节拍的总数。 启动时, 内核将该变量初始化为 0, 每次时钟中断处理程序都会增加该变量的值。
因为一秒内时钟中断的次数等于 Hz, 所以 jiffes 一秒内增加的值为 Hz, 系统运行时间以秒为单位计算, 就等于time = jiffes/Hz( jiffes = seconds*HZ)
jiffies 定义在文件 include/linux/jiffies.h 中
- extern u64 __jiffy_data jiffies_64;
- extern unsigned long volatile __jiffy_data jiffies;
jiffies_64 和 jiffies 是同一个东西, jiffies_64 用于 64 位系统, 而 jiffies 用于 32 位系统。关键字 volatile 指示编译器在每次访问变量时都重新从主内存中获得, 而不是通过寄存器中的变量别名访
问, 从而确保前面的循环能按预期的方式执行。
当访问 jiffies 的时是访问的是 jiffies_64 的低 32 位,使用 get_jiffies_64 这个函数可以获取 jiffies_64 的值。在 32 位的系统上读取 jiffies 的值,在 64 位的系统上 jiffes 和 jiffies_64
表示同一个变量,因此也可以直接读取 jiffies 的值。所以不管是 32 位的系统还是 64 位系统,
都可以使用 jiffies。
jiffies 变量总是无符号长整型(unsigned long), 因此, 在 32 位体系结构上是 32 位, 在时钟频率为 100的情况下, 497 天后会溢出, 如果频率是 1000, 49.7 天后会溢出。
当 jiffies 变量的值超过它的最大存放范围后就会发生溢出, 对于 32 位无符号长整型, 最大取值为 2^32-1,在溢出前, 定时器节拍计数最大为 4294967295, 如果节拍数达到了最大值后还要继续增加的话, 它的值会回绕到 0。
处理绕回API 函数
如果 unkown 超过 known 的话, time_after 函数返回真, 否则返回假。
如果 unkown 没有超过 known的话 time_before 函数返回真, 否则返回假。
time_after_eq 函数在time_after上,多判断了等于这个条件, time_before_eq 也类似。
判断某段代码执行时间有没有超时
- unsigned long timeout;
- timeout = jiffies + (2 * HZ); /* 超时的时间点 */
- ....
-
- /* 判断有没有超时 */
- if(time_before(jiffies, timeout))
- {
- /* 超时未发生 */
- }
- else
- {
- /* 超时发生 */
- }
timeout 就是超时时间点,比如要判断代码执行时间是不是超过了 2 秒,那么超时时间点就是 jiffies+(2*HZ),如果 jiffies 大于 timeout 那就表示超时了,否则就是没有超时。
为了方便开发, Linux 内核提供了几个 jiffies 和 ms、 us、 ns 之间的转换函数
①定时 10ms
jiffies +msecs_to_jiffies(10)②定时 10us
jiffies +usecs_to_jiffies(10)
Linux 内核定时器采用系统时钟来实现,只需要提供超时时间(定时值)和定时处理函数即可。
当超时时间到了后设置的定时处理函数就会执行。在使用内核定时器的时候要注意一点,内核定时器并不是周期性运行的,超时以后就会自动关闭,因此如果想要实现周期性定时,那么就需要在定时处理函数中重新开启定时器。
Linux 内核使用 timer_list 结构体表示内核定时器, timer_list 定义在文件include/linux/timer.h 中
- struct timer_list
- {
- struct list_head entry;
- unsigned long expires; /* 定时器超时时间, 单位是节拍数 */
- struct tvec_base *base;
- void (*function)(unsigned long); /* 定时处理函数指针 */
- unsigned long data; /* 要传递给 function 函数的参数 */
- int slack;
- };
要使用内核定时器首先要先定义一个 timer_list 变量, 表示定时器, tiemr_list 结构体的 expires 成员变量表示超时时间, 单位为节拍数。
定义一个周期为 2 秒的定时器,这个定时器的超时时间是 jiffies+(2*HZ),expires=jiffies+(2*HZ)。 function 是定时器超时以后的定时处理函数,要做的工作就放到这个函数里面, 需要编写这个定时处理函数。
内核定时器API
内核定时器使用流程
- struct timer_list timer; /* 定义定时器 */
-
- /* 定时器回调函数 */
- void function(unsigned long arg)
- {
- 定时器处理代码
-
- //如果需要定时器周期性运行的话就使用 mod_timer函数重新设置超时值并且启动定时器。
- mod_timer(&dev->timertest, jiffies + msecs_to_jiffies(2000));
-
- }
-
- /* 初始化函数 */
- void init(void)
- {
- init_timer(&timer); /* 初始化定时器 */
- timer.function = function; /* 设置定时处理函数 */
- timer.expires=jffies + msecs_to_jiffies(2000);/* 超时时间 2 秒 */
- timer.data = (unsigned long)&dev; /* 将设备结构体作为参数,传给定时器回调函数参数 */
- add_timer(&timer); /* 启动定时器 */
- }
-
- /* 退出函数 */
- void exit(void)
- {
- del_timer(&timer); /* 删除定时器 */
- /* 或者使用 */
- del_timer_sync(&timer);
- }
Linux 内核短延时函数,Linux 内核提供了毫秒、微秒和纳秒延时函数
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。