linux内核时间&定时器&延时

1、内核时间

1.1节拍率(tick rate)

在内核中指定了一个变量HZ,内核初始化的时候会根据这个值确定定时器的节拍率。

HZ定义在 include/asm-generic/param.h

bash 复制代码
-> Kernel Features -> Timer frequency ( [=y])
  • 高节拍内核定时器能够以更高的频率和更高的准确度运行,依赖定时器执行的系统调用,比如poll()和select(),运行的精度更高
  • 高节拍率提高进程抢占的准确度(缩短了调度延时,如果进程还剩2ms时间片,在10ms的调度周期下,进程会多运行8ms。 由于耽误了抢占,对于一些对时间要求严格的任务会产生影响)
  • 节拍率越高,系统负担越重。

1.2 jiffies

Linux 内核使用全局变量 jiffies 来记录系统从启动以来的系统节拍数,系统启动的时候会将 jiffies 初始化为 0,每次时钟中断处理程序都会增加该变量的值,jiffies 定义在文件include/linux/jiffies.h 中

c 复制代码
extern u64 __jiffy_data jiffies_64;
extern unsigned long volatile __jiffy_data jiffies;

因此在32位体系结构上是32位,而在64位体系上是64位。对于32位的jiffies,如果HZ为1000,49.7天后会溢出。虽然溢出的情况不常见,但程序在检测超时时仍然可能因为回绕而导致错误。linux提供了4个宏来比较节拍计数,它们能正确地处理节拍计数回绕。

2、内核短延时

2.1

c 复制代码
#include <linux/jiffies.h>
#define time_after(unknown, known)    // unknow > known
#define time_before(unknown, known)   // unknow < known
#define time_after_eq(unknown, known)  // unknow >= known
#define time_before_eq(unknown, known)  // unknow <= known

unkown 通常为 jiffies,known 通常是需要对比的值

如果 unkown 超过 known 的话,time_after 函数返回真,否则返回假。如果 unkown 没有超

过 known 的话 time_before 函数返回真,否则返回假。time_after_eq 函数和 time_after 函数类似,

只是多了判断等于这个条件。同理,time_before_eq 函数和 time_before 函数也类似。

jiffies和msecs以及usecs的转换:

c 复制代码
unsigned int jiffies_to_msecs(const unsigned long);
unsigned int jiffies_to_usecs(const unsigned long);
unsigned long msecs_to_jiffies(const unsigned int m);
unsigned long usecs_to_jiffies(const unsigned int u);

2.2

阻塞

c 复制代码
#include <linux/delay.h>
void ndelay(unsigned long nsecs); /*延迟纳秒 */
void udelay(unsigned long usecs); /*延迟微秒 */
void mdelay(unsigned long msecs); /*延迟毫秒 */

3 内核休眠延时

非原子环境的睡眠,用于不需要特别精确的长短延时

c 复制代码
#include <linux/delay.h>
void usleep_range(unsigned long min, unsigned long max);//用于微秒级别的休眠
void msleep(unsigned int msecs); //用于毫秒级别的休眠

unsigned long msleep_interruptible(unsigned int msecs);
//与 msleep 类似,但任务进入 TASK_INTERRUPTIBLE 状态。如果在休眠期间接收到信号,它会提前被唤醒。

void ssleep(unsigned int seconds);
//用于秒级别的休眠。msleep 的宏实现,参数单位是秒.任务同样处于 TASK_UNINTERRUPTIBLE 状态。

4、内核定时器

可以理解为ucos的软定时器。

  • 内核定时器并不是周期性运行的,超时以后就会自动关闭。此如果想要实现周期性定时,那么就需要在定时回调处理函数中重新开启定时器

include/linux/timer.h

c 复制代码
struct timer_list {
	 struct list_head entry;
	 unsigned long expires; /* 定时器超时时间,单位是节拍数 */
	 struct tvec_base *base;
	 void (*function)(unsigned long); /* 定时处理函数 */
	 unsigned long data; /* 要传递给 function 函数的参数 */
	 int slack;
};

4.1 API函数接口

函数 描述
timer_list 定义定时器timer_list 变量
init_timer 初始化 timer_list 类型变量
add_timer 用于向 Linux 内核注册定时器,注册以后,定时器就会开始运行
del_timer 删除一个定时器
del_timer_sync 等待其他处理器使用完定时器再删除,del_timer_sync 不能使用在中断上下文中
mod_timer 于修改定时值,如果定时器还没有激活,mod_timer 函数会激活定时器
c 复制代码
timer.function = function; /* 设置定时处理函数 */
timer.data = (unsigned long)&dev; /* 将设备结构体作为参数 */
timer.expires=jffies + msecs_to_jiffies(2000);//
add_timer(&timer); /* 启动定时器//mod_timer(&timer, jiffies + msecs_to_jiffies(val)); 

4、schedule_timeout()

c 复制代码
set_current_state(TASK_INTERRUPTIBLE);      /* 将任务设置为可中断睡眠状态   */
schedule_timeout(s *HZ);        /* 睡眠,s秒后唤醒   */

5、高精度定时器(hrtimers)延时(未完)

总结

机制 精度 是否让出 CPU 适用上下文 主要用途
ndelay/udelay/mdelay 否(忙等待) 任何(慎用) 极短延时,原子上下文
usleep_range 进程上下文 不精确的短延时,电源优化
msleep/ssleep 进程上下文 长时间的休眠
hrtimer 非常高 任何 高精度延时或定时任务
内核定时器 低(基于HZ) 任何 在未来某个时间点执行函数
相关推荐
计算机安禾2 分钟前
【Linux从入门到精通】第36篇:DNS服务探秘——自己搭建一个内网DNS
linux·运维·servlet
2023自学中10 分钟前
make clean 与 make distclean
linux·嵌入式
BenD-_-41 分钟前
CVE-2026-31431 Copy Fail:Linux 内核本地提权漏洞风险与缓解
linux·网络·安全
Web极客码1 小时前
2026年Linux VPS安全加固清单:SSH、防火墙与审计就绪配置
运维·服务器·数据库
无敌的黑星星1 小时前
Java8 CompletableFuture 实战指南
linux·前端·python
星恒讯工业路由器1 小时前
配网自动化多网融合应用解决方案
运维·自动化
前端技术1 小时前
03_网络层与IP编址:理解网络寻址的核心逻辑
服务器·网络·php
智慧物业老杨1 小时前
智慧物业收费系统的数智化落地实践:从人工硬扛到自动化闭环
运维·自动化
Championship.23.242 小时前
Linux Top 命令族深度解析与实战指南
java·linux·服务器·top·linux调试
techdashen2 小时前
Cloudflare 为何抛弃 NGINX,用 Rust 自研了一个代理
运维·nginx·rust