linux内核定时器

文章目录

  • 一、jiffies定时器
    • 1.1 工作原理
    • 1.2 timer_list结构体
    • 1.3 相关接口
      • 1.3.1 初始化和启动定时器
      • 1.3.2 修改定时器
      • 1.3.3 删除定时器
      • 1.3.4 jiffies相关接口
  • 二、高精度定时器
    • 2.1 hrtimer结构体
    • 2.2 相关接口
      • 2.2.1 初始化和启动定时器
      • 2.2.2 取消定时器
      • 2.2.3 通过定时器实现周期性任务

一、jiffies定时器

传统定时器(基于jiffies)是Linux内核中最早和最基本的定时机制。jiffies是一个全局变量,它记录了自系统启动以来的“滴答数”(ticks)。每次时钟中断发生时,jiffies会增加。这个机制基于系统时钟中断的频率,因此其精度受到时钟频率的限制。

1.1 工作原理

  1. 时钟中断:
    时钟中断是一个固定频率的周期性中断事件,每次时钟中断发生时,内核会增加jiffies的值;
    时钟频率通常由宏HZ定义,比如HZ=1000表示每秒发生1000次时钟中断(每毫秒一次);
  2. jiffies变量:
    jiffies是一个全局变量,用于记录自系统启动以来的时钟中断次数;
    在每次时钟中断处理过程中,内核会增加jiffies的值;

1.2 timer_list结构体

传统定时器使用struct timer_list结构体来定义和管理定时器任务。

struct timer_list {struct hlist_node entry;unsigned long expires; // 定时器到期的jiffies值void (*function)(unsigned long); // 定时器回调函数unsigned long data; // 回调函数参数
};

1.3 相关接口

定时器相关接口定义在kernel\time\timer.c文件中。主要流程涉及以下接口。

1.3.1 初始化和启动定时器

使用add_timer接口启动定时器,参数是timer_list

void add_timer(struct timer_list *timer)

代码示例:

#include <linux/timer.h>
#include <linux/jiffies.h>static struct timer_list my_timer;void my_timer_callback(unsigned long data)
{printk(KERN_INFO "Timer callback function called with data: %lu\n", data);
}void setup_timer(void)
{// 初始化定时器init_timer(&my_timer);my_timer.function = my_timer_callback;my_timer.data = 0; // 回调函数参数my_timer.expires = jiffies + HZ; // 1秒后到期// 添加定时器到内核add_timer(&my_timer);
}

类似的接口还有add_timer_on,该接口功能是在指定的cpu上启动一个定时器:

void add_timer_on(struct timer_list *timer, int cpu)

1.3.2 修改定时器

使用mod_timer接口修改定时器的超时时间:

void my_timer_callback(unsigned long data)
{printk(KERN_INFO "Timer callback function called with data: %lu\n", data);// 如果需要周期性定时器, 使用mod_timer修改定时器超时时间mod_timer(&my_timer, jiffies + msecs_to_jiffies(500));
}

在上述定时器回调接口my_timer_callback中,调用mod_timer修改定时器的超时时间为500ms,这样能给实现每隔500ms循环调用定时器超时回调接口。
mod_timer接口的功能相当于del_timer(timer); timer->expires = expires; add_timer(timer);,即删除定时器、设置定时器超时时间、启动定时器。

1.3.3 删除定时器

使用del_timer接口删除定时器:

del_timer(&my_timer);

1.3.4 jiffies相关接口

上述定时器单位是以jiffies为单位的,添加定时器和修改定时器的超时时间,都是以jiffies为单位的。下面介绍几个常用的jiffies与其它时间单位转化的接口:

static __always_inline unsigned long msecs_to_jiffies(const unsigned int m);
unsigned int jiffies_to_msecs(const unsigned long j);
static __always_inline unsigned long usecs_to_jiffies(const unsigned int u);
unsigned int jiffies_to_usecs(const unsigned long j);static inline unsigned long timespec_to_jiffies(const struct timespec *value);
static inline void jiffies_to_timespec(const unsigned long jiffies,struct timespec *value);unsigned long timeval_to_jiffies(const struct timeval *value);
void jiffies_to_timeval(const unsigned long jiffies, struct timeval *value);

二、高精度定时器

传统定时器的精度和实时性受限于系统的时钟中断频率和调度机制;
相对于传统定时器(jiffies),高精度定时器可以提供纳秒级的定时精度,适用于实时应用、精确计时等需求;

2.1 hrtimer结构体

struct hrtimer {struct timerqueue_node node; // 定时器队列节点ktime_t _softexpires;        // 定时器到期时间enum hrtimer_restart (*function)(struct hrtimer *); // 回调函数enum hrtimer_mode state;     // 定时器状态clockid_t clock_id;          // 使用的时钟类型
};

2.2 相关接口

2.2.1 初始化和启动定时器

linux中,可以使用hrtimer_init接口初始化一个高精度定时器;
使用hrtimer_start接口启动定时器;
示例代码:

#include <linux/hrtimer.h>
#include <linux/ktime.h>
#include <linux/module.h>
#include <linux/init.h>static struct hrtimer my_hrtimer;enum hrtimer_restart my_timer_callback(struct hrtimer *timer)
{printk(KERN_INFO "High-Resolution Timer Callback\n");// 如果需要周期性定时器,重新启动定时器hrtimer_forward_now(timer, ns_to_ktime(1000000000)); // 1秒return HRTIMER_RESTART;
}void setup_hrtimer(void)
{ktime_t ktime;// 初始化高精度定时器hrtimer_init(&my_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);my_hrtimer.function = &my_timer_callback;// 设置定时器到期时间ktime = ktime_set(0, 1000000000); // 1秒hrtimer_start(&my_hrtimer, ktime, HRTIMER_MODE_REL);
}

在示例代码中,使用hrtimer_init初始化一个定时器,使用hrtimer_start接口设置定时器超时时间是 1s 并启动定时器。

2.2.2 取消定时器

当模块卸载或者不需要定时器时,使用hrtimer_cancel接口取消定时器:

ret = hrtimer_cancel(&my_hrtimer);

2.2.3 通过定时器实现周期性任务

在定时器回调函数接口中,使用hrtimer_start 重启启动定时器,或者使用hrtimer_forward_now 接口更新定时器的到期时间,都能够实现周期性任务。

hrtimer_forward_now:将定时器的到期时间向前推进一个时间间隔;适合保持固定周期,即使回调函数的执行时间可能有波动。
hrtimer_start:重新启动定时器,可以灵活地设置新的到期时间;适用于需要在每次回调函数中动态调整定时器时间的场景。

代码示例:

enum hrtimer_restart my_timer_callback(struct hrtimer *timer)
{printk(KERN_INFO "High-Resolution Timer Callback\n");// 如果需要周期性定时器,重新启动定时器// 方法一:hrtimer_forward_now(timer, ns_to_ktime(1000000000)); // 1秒// 方法二:hrtimer_start(&my_hrtimer, ktime, HRTIMER_MODE_REL);return HRTIMER_RESTART;
}

注意:

  • 虽然 hrtimer 提供纳秒级的精度,但是实际精度受硬件和系统调度的影响,会导致定时器实际触发的时间可能会有稍微的偏差;
  • 这就导致使用hrtimer_start接口实现周期性任务时,每次产生一些偏差,可能会产生累计误差;
  • hrtimer_forward_now接口是在定时器当前这次理论到期时间基础上,向前推进一个周期设置下次超时时间,所以不会有累积误差。如果对周期性的时间准确性有要求,建议使用hrtimer_forward_now接口。

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

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

相关文章

shell-awk语法整理

shell-awk语法整理 前言基本语法内置变量1. $02. NF3. NR4. FS5. RS6. OFS7. ORS8. FILENAME9. FNR10. ARGV11. ENVIRON12. IGNORECASE13. RSTART 和 RLENGTH示例解释 内置函数循环语句&#xff08;后面的;可不加&#xff09;条件语句高级特性示例 特殊模式BEGINEND组合示例BEG…

R语言实战—圆形树状图

话不多说&#xff0c;先看最终效果&#xff1a; 圆形树状图是树状图的一个变型&#xff0c;其实都是层次聚类。 接下来看代码步骤&#xff1a; 首先要先安装两个包&#xff1a; install.packages("ggtree") install.packages("readxl") 咱就别问问什么…

29、php实现和为S的两个数字(含源码)

题目&#xff1a;php 实现 和为S的两个数字 描述&#xff1a; 输入一个递增排序的数组和一个数字S&#xff0c;在数组中查找两个数&#xff0c; 是的他们的和正好是S&#xff0c;如果有多对数字的和等于S&#xff0c;输出两个数的乘积最小的。 输出描述&#xff1a; 对应每个测…

go zero入门

一、goctl安装 goctl 是 go-zero 的内置脚手架&#xff0c;可以一键生成代码、文档、部署 k8s yaml、dockerfile 等。 # Go 1.16 及以后版本 go install github.com/zeromicro/go-zero/tools/goctllatest检查是否安装成功 $ goctl -v goctl version 1.6.6 darwin/amd64vscod…

vue2响应式原理+模拟实现v-model

效果 简述原理 配置对象传入vue实例 模板解析&#xff0c;遍历出所有文本节点&#xff0c;利用正则替换插值表达式为真实数据 data数据代理给vue实例&#xff0c;以后通过this.xxx访问 给每个dom节点增加观察者实例&#xff0c;由观察者群组管理&#xff0c;内部每一个键值…

sqlite 数据库 介绍

文章目录 前言一、什么是 SQLite &#xff1f;二、语法三、SQLite 场景四、磁盘文件 前言 下载 目前已经出到了&#xff0c; Version 3.46.0 SQLite&#xff0c;是一款轻型的数据库&#xff0c;是遵守ACID的关系型数据库管理系统&#xff0c;它包含在一个相对小的C库中。它是…

VMware虚拟机配置桥接网络

转载&#xff1a;虚拟机桥接网络配置 一、VMware三种网络连接方式 VMware提供了三种网络连接方式&#xff0c;VMnet0, VMnet1, Vmnet8&#xff0c;分别代表桥接&#xff0c;Host-only及NAT模式。在VMware的编辑-虚拟网络编辑器可看到对应三种连接方式的设置&#xff08;如下图…

美好生活的 100 条建议

简介 一些简洁明了的人生建议&#xff0c;易于理解&#xff0c;并且能够为日常生活中的各个方面提供实用的指导。 财富 (Possessions) 1. If you want to find out about people’s opinions on a product, google \reddit. You’ll get real people arguing, as compared t…

SpringBoot2.2.6使用spring-boot-validation读取不到自定义配置文件中的属性

SpringBoot2.2.6没有做message.properties文件中属性的自动读取配置。解决方法有两种&#xff1a; 1. 升级springboot版本到2.6.x以上 2. 在现有springboot版本的基础上添加以下自定义配置&#xff1a; Configuration public class RequestParamValidationConfig implements…

学习笔记——交通安全分析12

目录 前言 当天学习笔记整理 4信控交叉口交通安全分析 结束语 前言 #随着上一轮SPSS学习完成之后&#xff0c;本人又开始了新教材《交通安全分析》的学习 #整理过程不易&#xff0c;喜欢UP就点个免费的关注趴 #本期内容接上一期11笔记 当天学习笔记整理 4信控交叉口交…

ORA-03115 ORA-06594--空间不足 rman 磁带压缩备份 控制文件恢复后备份信息丢失

---用旧的控制文件恢复后 这个控制文件本身的备份信息不在此还原出的控制文件中。所以这个备份的控制文件就删不掉&#xff0c;看不到。 但是只要设置正确的dbid&#xff0c;还是可以用恢复这个控制文件的 正常未恢复过controlfile的话&#xff0c;这个控制文件备份信息在现有…

Square Root SAM论文原理

文章目录 Square Root SAM论文原理核心原理SLAM问题的3种表示贝叶斯网络因子图&#xff08;Factor graph&#xff09;马尔科夫随机场(Markov Random Field, MRF) SLAM最小二乘问题&线性化因式分解 factorization矩阵与图(Matrices ⇔ Graphs)因式分解&变量消元(Factori…

Kafka系列之Kafka知识超强总结

一、Kafka简介 Kafka是什么 Kafka是一种高吞吐量的分布式发布订阅消息系统&#xff08;消息引擎系统&#xff09;&#xff0c;它可以处理消费者在网站中的所有动作流数据。 这种动作&#xff08;网页浏览&#xff0c; 搜索和其他用户的行动&#xff09;是在现代网络上的许多社…

14-22 剑和远方2 - 深度神经网络中的学习机制

概论 在第一部分中&#xff0c;我们深入探讨了人工智能的兴衰简史以及推动人工智能发展的努力。我们研究了一个简单的感知器&#xff0c;以了解其组件以及简单的 ANN 如何处理数据和权重层。在简单的 ANN 中&#xff0c;不会对数据执行特定操作。ANN 中的激活函数是一个线性函…

Surface splatting (2D Gaussian splatting)代码分析

源码地址 colab.research.google.com/drive/1qoclD7HJ3-o0O1R8cvV3PxLhoDCMsH8W 核心代码 surface_splatting def surface_splatting(means3D, scales, quats, colors, opacities, intrins, viewmat, projmat):# Rasterization setupprojmat torch.zeros(4,4).cuda()projm…

flask使用定时任务flask_apscheduler(APScheduler)

Flask-APScheduler描述: Flask-APScheduler 是一个 Flask 扩展&#xff0c;增加了对 APScheduler 的支持。 APScheduler 有三个内置的调度系统可供您使用&#xff1a; Cron 式调度&#xff08;可选开始/结束时间&#xff09; 基于间隔的执行&#xff08;以偶数间隔运行作业…

c#中的超时终止

在C#中&#xff0c;可以使用CancellationToken和Task的超时机制来实现调用方法时的超时终止。 一 用Task.Delay(int)模拟耗时操作 static async Task Main(string[] args){using (var cts new CancellationTokenSource(1 * 1000)){await doSomething(cts.Token);}Console.Wr…

移动校园(7)ii:uniapp响应拦截器处理token,以及微信小程序报错当前页面正在处于跳转状态,请稍后再进行跳转....

依据昨天的写完&#xff0c;在token过期之后&#xff0c;再次调用接口&#xff0c;会触发后端拦截&#xff0c;扔进全局错误处理中间件 前端说明提示都没有&#xff0c;只有一个这个&#xff0c;现在优化一下&#xff0c;再写一个类似全局后置守卫&#xff0c;当状态码是401的时…

RAID 冗余磁盘阵列

RAID也是Linux操作系统中管理磁盘的一种方式。 只有Linux操作系统才支持LVM的磁盘管理方式。 而RAID是一种通用的管理磁盘的技术&#xff0c;使用于多种操作系统。 优势&#xff1a;提升数据的读写速度&#xff0c;提升数据的可靠性。具体实现哪什么功能&#xff0c;要看你所…

RGB树-美团2023笔试(codefun2000)

题目链接 RGB树-美团2023笔试(codefun2000) 题目内容 塔子哥是一位著名的冒险家&#xff0c;他经常在各种森林里探险。今天&#xff0c;他来到了道成林&#xff0c;这是一片美丽而神秘的森林。在探险途中&#xff0c;他遇到了一棵 n 个节点的树&#xff0c;树上每个节点都被涂…