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,一经查实,立即删除!

相关文章

R语言实战—圆形树状图

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

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;如下图…

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 中的激活函数是一个线性函…

flask使用定时任务flask_apscheduler(APScheduler)

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

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

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

RAID 冗余磁盘阵列

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

LVGL移植与VS模拟器使用

一、移植文件介绍 二、移植部分 第一步&#xff1a;创建LVGL文件夹 第二步&#xff1a; 构造LVGL文件夹&#xff1a;LVGL - GUI - lvgl - 第三步&#xff1a;添加文件 3.1 从examples中添加2个.c文件 3.2 从src中添加文件 draw文件 extra文件 第四步&#xff1a; 三、Ke…

Linux系统安装软件包的方法rpm和yum详解

起因&#xff1a; 本篇文章是记录学习Centos7的历程 关于rpm 常见命令 1&#xff09;查看已经安装的软件包 rpm -q 软件包名 2&#xff09;查看文件的相关信息 rpm -qi 软件包名 3&#xff09;查看软件包的依赖关系 就是说要想安装这个软件包&#xff0c;就必须把一些前…

三级_网络技术_04_中小型网络系统总体规划与设计

1.下列关于路由器技术特征的描述中&#xff0c;正确的是()。 吞吐量是指路由器的路由表容量 背板能力决定了路由器的吞吐量 语音、视频业务对延时抖动要求较低 突发处理能力是以最小帧间隔值来衡量的 2.下列关于路由器技术特征的描述中&#xff0c;正确的是()。 路由器的…

springboot公寓租赁系统-计算机毕业设计源码03822

摘要 1 绪论 1.1 研究背景与意义 1.2选题背景 1.3论文结构与章节安排 2 公寓租赁系统系统分析 2.1 可行性分析 2.1.1 技术可行性分析 2.1.2 经济可行性分析 2.1.3 法律可行性分析 2.2 系统功能分析 2.2.1 功能性分析 2.2.2 非功能性分析 2.3 系统用例分析 2.4 系…

韦东山嵌入式linux系列-第一个实验

1 前言 笔者使用的是韦东山STM32MP157 Pro的板子&#xff0c;环境搭建部分按照说明文档配置完成。配置桥接网卡实现板子、windows、ubuntu的通信&#xff0c;也在开发板挂载 Ubuntu 的NFS目录 &#xff0c;这里就不再赘述了。 板子: 192.168.5.9 windows: 192.168.5.10 ubunt…

机械键盘如何挑选

机械键盘的选择是一个关键的决策&#xff0c;因为它直接影响到我们每天的打字体验。在选择机械键盘时&#xff0c;有几个关键因素需要考虑。首先是键盘的键轴类型。常见的键轴类型包括蓝轴、红轴、茶轴和黑轴等。不同的键轴类型具有不同的触发力、触发点和声音。蓝轴通常具有明…

聚类分析方法(一)

目录 一、聚类分析原理&#xff08;一&#xff09;聚类分析概述&#xff08;二&#xff09;聚类的数学定义&#xff08;三&#xff09;簇的常见类型&#xff08;四&#xff09;聚类框架及性能要求&#xff08;五&#xff09;簇的距离 二、划分聚类算法&#xff08;一&#xff0…

Java 有什么必看的书?

Java必看经典书有这两本&#xff1a; 1、Java核心技术速学版&#xff08;第3版&#xff09; 经典Java开发基础书CoreJava速学版本&#xff01;Java入门优选书籍&#xff0c;更新至Java17&#xff0c;内容皆是精华&#xff0c;让Java学习更简单&#xff0c;让Java知识应用更快速…

【Linux】什么是进程间通信?方式有哪些?本质理解?

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …