最便宜服装网站建设,合肥建网站的公司,做网站直播平台,另外网站是做的IPv4还是IPv6目录
内核时间管理
系统节拍率
高/低节拍率的优缺点
jiffies 节拍数
时间绕回
时间转换函数
内核定时器
timer_list 结构体
定时器API函数
init_timer 函数
add_timer 函数
del_timer 函数
del_timer_sync 函数
mod_timer 函数
Linux 内核短延时函数 内核时间管…目录
内核时间管理
系统节拍率
高/低节拍率的优缺点
jiffies 节拍数
时间绕回
时间转换函数
内核定时器
timer_list 结构体
定时器API函数
init_timer 函数
add_timer 函数
del_timer 函数
del_timer_sync 函数
mod_timer 函数
Linux 内核短延时函数 内核时间管理
Linux 内核中有大量的函数需要时间管理比如周期性的调度程序、延时程序最常用的就是定时器。
系统节拍率
硬件定时器提供时钟源时钟源的频率可以设置 设置好以后就周期性的产生定时中断系统使用定时中断来计时。
中断周期性产生的频率就是系统频率也叫做节拍率(tick rate)。
在编译 Linux 内核的时候可以通过图形化界面设置系统节拍率按照如下路径打开配置界面
- Kernel Features - Timer frequency (choice [y])
选中“Timer frequency”可选的系统节拍率如下 默认情况下选择 100Hz。
设置好以后打开 Linux 内核源码根目录下的.config 文件可以找到相关宏定义 宏定义CONFIG_HZ 为 100 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表示一秒的节拍数也就是频率。
宏 HZ 就是 CONFIG_HZ因此 HZ100。
高/低节拍率的优缺点 高节拍率通常 ≥1000Hz如1000Hz1ms/次 低节拍率通常 ≤100Hz如100Hz10ms/次 高节拍率会提高系统时间精度但也会导致中断的产生更加频繁从而加剧系统的负担。
所以需要根据项目的实际情况选择合适的系统节拍率。
jiffies 节拍数
Linux 内核使用全局变量 jiffies 来记录系统从启动以来的系统节拍数系统启动的时候会将 jiffies 初始化为 0。
jiffies 定义在文件 include/linux/jiffies.h 中定义如下
extern u64 __jiffy_data jiffies_64;
extern unsigned long volatile __jiffy_data jiffies;
jiffies_64 用于 64 位系统而 jiffies 用于 32 位系统 HZ 表示每秒的节拍数 jiffies 表示系统运行的 jiffies 节拍数所以 jiffies/HZ 就是系统运行时间单位为秒。
时间绕回
不管是 32 位还是 64 位的 jiffies都有溢出的风险溢出以后会重新从 0 开始计数。
存储限制 32位jiffies最大值 0xFFFFFFFF约49.7天溢出 64位jiffies理论永不溢出5.8 亿年实际内核仍做防御性编程
// 32位无符号整数溢出示例
u32 jiffies 0xFFFFFFFE;
jiffies 3; // 结果变为1非5
Linux 内核提供了API 函数来处理绕回 我们要判断某段代码执行时间有没有超时可以使用如下所示代码
unsigned long timeout;
timeout jiffies (2 * HZ); /* 超时的时间点 *//*************************************
具体的代码
************************************//* 判断有没有超时 */
if(time_before(jiffies, timeout)) {/* 超时未发生 */
} else {/* 超时发生 */
}
timeout 就是超时时间点通过函数 time_before 来判断 jiffies 是否小于 timeout如果小于的话就表示没有超时。
时间转换函数
Linux 内核提供了几个 jiffies 和 ms、 us、 ns 之间的转换函数如表 这些函数使用的示例代码如下
#include linux/jiffies.h
#include linux/ktime.hvoid time_conversion_demo(void) {unsigned long jiffies_value;u64 nanoseconds;unsigned int milliseconds, microseconds;/* 示例1jiffies转时间单位 */jiffies_value jiffies; // 获取当前jiffies值// 转换为毫秒/微秒/纳秒milliseconds jiffies_to_msecs(jiffies_value);microseconds jiffies_to_usecs(jiffies_value);nanoseconds jiffies_to_nsecs(jiffies_value);printk(KERN_INFO Current jiffies: %lu\n, jiffies_value);printk(KERN_INFO Converted to: %u ms, %u us, %llu ns\n, milliseconds, microseconds, nanoseconds);/* 示例2时间单位转jiffies */milliseconds 1000; // 1秒microseconds 1000000; // 1秒nanoseconds 1000000000; // 1秒// 转换为jiffiesjiffies_value msecs_to_jiffies(milliseconds);printk(KERN_INFO %u ms %lu jiffies\n, milliseconds, jiffies_value);jiffies_value usecs_to_jiffies(microseconds);printk(KERN_INFO %u us %lu jiffies\n, microseconds, jiffies_value);jiffies_value nsecs_to_jiffies(nanoseconds);printk(KERN_INFO %llu ns %lu jiffies\n, nanoseconds, jiffies_value);/* 示例3混合使用场景 */// 设置2秒后的超时点考虑HZ可能不同unsigned long timeout jiffies msecs_to_jiffies(2000);printk(KERN_INFO Timeout at jiffies: %lu\n, timeout);
}
内核定时器
Linux 内核定时器采用系统时钟来实现内核定时器并不是周期性运行的超时以后就会自动关闭。
因此如果想要实现周期性定时那么就需要在定时处理函数中重新开启定时器。
timer_list 结构体
Linux 内核使用 timer_list 结构体表示内核定时器。
timer_list 定义在文件include/linux/timer.h 中定义如下
struct timer_list {struct list_head entry; // 链表节点用于加入定时器队列unsigned long expires; // 超时时间基于jiffies的绝对时间struct tvec_base *base; // 关联的定时器管理基类void (*function)(unsigned long); // 回调函数指针unsigned long data; // 传递给回调函数的参数int slack; // 允许的时间误差优化用
};
典型使用流程如下 定时器API函数
linux 内核定时器常用的 API 函数如下 init_timer 函数
init_timer 函数负责初始化 timer_list 类型变量当我们定义了一个 timer_list 变量以后一定要先用 init_timer 初始化一下。
init_timer 函数原型如下
void init_timer(struct timer_list *timer)
timer要初始化定时器。
add_timer 函数
add_timer 函数用于向 Linux 内核注册定时器使用 add_timer 函数向内核注册定时器以后定时器就会开始运行。
add_timer函数原型如下
void add_timer(struct timer_list *timer)
timer要注册的定时器。
del_timer 函数
del_timer 函数用于删除一个定时器不管定时器有没有被激活都可以使用此函数删除。
在多处理器系统上定时器可能会在其他的处理器上运行因此在调用 del_timer 函数删除定时器之前要先等待其他处理器的定时处理器函数退出。
del_timer 函数原型如下
int del_timer(struct timer_list * timer)
timer要删除的定时器。返回值 0定时器还没被激活 1定时器已经激活。
del_timer_sync 函数
del_timer_sync 函数是 del_timer 函数的同步版会等待其他处理器使用完定时器再删除 del_timer_sync 不能使用在中断上下文中。
del_timer_sync 函数原型如下所示
int del_timer_sync(struct timer_list *timer)
timer要删除的定时器。返回值 0定时器还没被激活 1定时器已经激活。
mod_timer 函数
mod_timer 函数用于修改定时值如果定时器还没有激活的话 mod_timer 函数会激活定时器。
mod_timer 函数原型如下
int mod_timer(struct timer_list *timer, unsigned long expires)
timer要修改超时时间(定时值)的定时器。expires修改后的超时时间。返回值 0调用 mod_timer 函数前定时器未被激活 1调用 mod_timer 函数前定时器已被激活。
内核定时器一般的使用流程如下所示
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 内核种提供了毫秒、微秒和纳秒延时函数如表 使用示例如下
#include linux/delay.h // 必须包含的头文件void hardware_operations(void)
{/* 硬件寄存器写入后需要稳定时间 */writel(0x55AA, reg_addr);// 纳秒级延时通常用于信号电平稳定ndelay(100); // 延迟100纳秒/* 发送启动命令 */writel(0xCC33, cmd_reg);// 微秒级延时适合短时等待udelay(50); // 延迟50微秒/* 检查设备状态 */while (!(readl(status_reg) READY_BIT)) {// 毫秒级延时较长等待mdelay(1); // 每次循环延迟1毫秒}// 更长的延时不推荐在原子上下文使用mdelay(100); // 延迟100毫秒
}