目录

内核时间管理

系统节拍率

高/低节拍率的优缺点

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,因此 HZ=100。

高/低节拍率的优缺点

  • ​高节拍率​​:通常 ≥1000Hz(如1000Hz=1ms/次)

  • ​低节拍率​​:通常 ≤100Hz(如100Hz=10ms/次)

高节拍率会提高系统时间精度,但也会导致中断的产生更加频繁,从而加剧系统的负担。

所以需要根据项目的实际情况,选择合适的系统节拍率。

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.h>void time_conversion_demo(void) {unsigned long jiffies_value;u64 nanoseconds;unsigned int milliseconds, microseconds;/* 示例1:jiffies转时间单位 */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毫秒
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/918704.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/918704.shtml
英文地址,请注明出处:http://en.pswp.cn/news/918704.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

路由器数据控制管理层面安全

数据层面&#xff1a;FPM Flexible Packet MatchingFPM是CisCOIOS新一代的ACL根据任意条件&#xff0c;无无状态的匹配数据包的头部负载&#xff0c;或者全部分析协议&#xff0c;更易于规则的创建用于替代传统ACL&#xff0c;对特定恶意流量的基础架构过滤无状态ipv4单播不支持…

Vue内置组件全解析:从入门到面试通关

文章目录Vue内置组件全解析&#xff1a;从入门到面试通关引言&#xff1a;为什么需要内置组件&#xff1f;一、Vue内置组件全景图二、核心内置组件详解1. <component> - 动态组件2. <transition> - 过渡动画3. <keep-alive> - 组件缓存4. <slot> - 内容…

VUE+SPRINGBOOT从0-1打造前后端-前后台系统-会议记录

在当今快节奏的工作环境中&#xff0c;会议记录是每个职场人士都必须要面对的任务。传统的手动记录方式不仅效率低下&#xff0c;而且容易遗漏重要信息。随着Web技术的发展&#xff0c;基于浏览器的实时语音转写技术为会议记录提供了全新的解决方案。本文将详细介绍如何利用Web…

WEB3——水龙头,如何获得开发用的测试币、 Sepolia 测试币?

注意&#xff1a; 有些水龙头渠道&#xff0c;要求以太坊币至少有0.01ETH,设有这个门槛&#xff0c;下面并不是所有渠道都能领取到测试币&#xff0c;有些可能对领取测试币有要求&#xff0c;如果想获得获取以太坊币的方法&#xff0c;可以看我其他的文章。 本文整理了多个免费…

C++调试革命:时间旅行调试实战指南

还在为C的悬垂指针、内存泄漏和并发竞态抓狂&#xff1f;让调试器学会“时光倒流” 凌晨三点&#xff0c;std::thread创建的六个线程中有一个突然吞掉了你的数据&#xff0c;valgrind只告诉你“Invalid read”&#xff0c;而时间旅行调试&#xff08;TTD&#xff09;​​ 能让你…

mysql8.0笔记

1.DDL数据定义语言 DDL是什么——————创建、修改、删除 数据库和表结构的命令。 基本语法 针对数据库的操作 -- 创建数据库 CREATE DATABASE 数据库名; -- 比如 CREATE DATABASE myschool; --查看所有数据库 SHOW DATABASES; --使用某个数据库 USE myschool; -- 删除数据库…

大模型微调【1】之入门

文章目录说明一 大模型微调技术1.1 微调基础1.2 量化概念1.3 高效微调方法LoRA&QLoRA1.4 LoRA VS QLoRA1.5 高效微调的应用场景二 主流微调工具2.1 unsloth2.2 LLama-Factory2.3 ms-SWIFT2.4 ColossalAI2.5 底层微调框架推荐2.6 模型性能评估框架EvalScope三 微调所需软硬件…

深入解析Linux poll()系统调用

&#x1f504; Linux poll() 系统调用详解一、poll 是干什么的&#xff1f;poll 是 Linux&#xff08;及 POSIX 标准&#xff09;中用于实现 I/O 多路复用&#xff08;I/O Multiplexing&#xff09; 的系统调用&#xff0c;它的核心作用是&#xff1a;让一个线程能够同时监视多…

文献阅读 | PLoS ONE | SRplot:一个免费的在线平台,用于数据可视化和图形

文献介绍文献题目&#xff1a; SRplot&#xff1a;一个免费的在线平台&#xff0c;用于数据可视化和图形 研究团队&#xff1a; Yewei Wang&#xff08;中南大学湘雅二医院&#xff09; 发表时间&#xff1a; 2023-11-09 发表期刊&#xff1a; PLoS ONE 影响因子&#xff1a; 3…

分布式与微服务宝典

分布式理论基础 1、分布式架构有哪些特点&#xff0c;优势和缺陷 特点&#xff1a;微服务架构的优点微服务架构的缺陷自由使用不同技术增加故障排除挑战每一个微服务都侧重于单一功能由于远程调用增加延迟支持单个可部署单元增加了配置与其他操作的工作量允许经常发布软件难以保…

利用生成式AI与大语言模型(LLM)革新自动化软件测试 —— 测试工程师必读深度解析

引言 自动化测试是现代软件工程的基石&#xff0c;然而&#xff0c;随着软件复杂度和迭代速度的飞速提升&#xff0c;传统自动化测试方法正面临越来越多的挑战。 近年来&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;和大语言模型&#xff08;LLM&#xff0…

JS 与 C++ 双向通信实战:基于 WebHostViewListener 的消息处理机制

前言在现代浏览器和桌面应用开发中&#xff0c;WebView 嵌入已经成为一种非常常见的 UI 技术方案。无论是基于 Chromium 的 CEF&#xff08;Chromium Embedded Framework&#xff09;、Qt WebEngine&#xff0c;还是自研浏览器内核&#xff0c;嵌入 WebView 都能带来极高的灵活…

模板打印技术——Office XLS 打印模板:为政务土地确权定制的纸张替换利器—仙盟创梦IDE

代码public static int cyberwin_replaceExcelandoutputPrint(string fisrcpathleurl, DataTable dtInfo, string despath){if (File.Exists(despath) true){//删除目标文件File.Delete(despath);}File.Copy(fisrcpathleurl, despath);string 目标文件 despath;MSEXCEL.Appli…

可直接运行的 Playwright C# 自动化模板

目录 目录结构 1. appsettings.json&#xff08;账号、URL、路径配置&#xff09; 2. Program.cs&#xff08;启动入口&#xff09; 3. SchedulerConfig.cs&#xff08;定时调度&#xff09; 4. SocialSecurityTask.cs&#xff08;自动报社保任务&#xff09; 5. QuerySo…

云平台监控-云原生环境Prometheus企业级监控实战

目录 一、基于 Kubernetes 的 Prometheus 监控方案概述 1. 核心组件及功能 2. 监控流程详解 3. 关键监控指标说明 二、Prometheus 与相关组件部署 1. 克隆项目代码 2. 安装 Prometheus Operator 3. 安装 Prometheus Stack 4. 查看容器运行状态 三、ServiceMonitor 配…

GPT-5 有点不太顺

GPT-5 有点不太顺 OpenAI 的新模型 GPT-5 盼了很久,结果一上线就问题不少。 发布会刚过,CEO 山姆・奥特曼就说,要给部分用户恢复 GPT-4o 这些老模型的使用权限,还承认 GPT-5 上线 “比预想的坎坷”。 简单题都做错了 不少用户发现,GPT-5 连一些简单问题都答不对,比之前…

《卷积神经网络(CNN):解锁视觉与多模态任务的深度学习核心》

1.概述卷积神经网络&#xff08;CNN&#xff09;是深度学习在计算机视觉领域的重要突破&#xff0c;专为处理网格状数据&#xff08;如图像&#xff09;设计&#xff0c;后也扩展到自然语言处理等领域。它解决了全连接网络处理大图像时计算代价高、特征保留差的问题&#xff0c…

React Native + Expo搭建APP项目+安卓模拟器

Expo 尝试一下就好&#xff0c;毕竟参考代码太少&#xff0c;相当于闭关造轮子&#xff0c;不建议。 一、需要的工具 1. node.js&#xff0c;推荐使用&#xff08;TLS版本&#xff09;&#xff0c;版本不是太低就行&#xff0c;测试用的v20.12.2的Node 2. 开发工具 VS CODE或…

第六十五章:AI的“精良食材”:图像标注、视频帧抽帧与字幕提取技巧

ai 数据处理前言&#xff1a;从“原始食材”到“AI盛宴”第一章&#xff1a;图像标注&#xff1a;为AI“指点江山”1.1 什么是图像标注&#xff1f;—— AI的“视觉标签”1.2 分类任务&#xff1a;图像的“身份识别”1.3 目标检测&#xff1a;图像的“区域识别”与“边界框”1.…

2025 开源语音合成模型全景解析:从工业级性能到创新架构的技术图谱

一、引言&#xff1a;开源浪潮下的语音合成技术跃迁 语音合成&#xff08;TTS&#xff09;作为人工智能领域的核心技术&#xff0c;近年来在开源社区的推动下取得了突破性进展。从早期的基于规则的拼接合成&#xff0c;到深度学习驱动的端到端模型&#xff0c;再到当前与大语言…