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.mfbz.cn/a/781759.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【qt】TCP 服务端怎么收到信息?

上一节,我已经讲了,TCP的监听,是基于上一节的,不知道的可以看看. 当我们的TCP 服务器 有 客户端请求连接的时候,会发出一个信号newConnection(). 在TCP服务端与客户端的通信中,我们需要使用到套接字 QTcpSocket类. 套接字相当于是网络通信的接口,服务段和客户端都要通过它进行通…

聚焦大模型应用落地,2024全球数字经济大会人工智能专题论坛在京举办

7月1日下午&#xff0c;2024全球数字经济大会人工智能专题论坛在中关村国家自主创新示范区会议中心举办。论坛紧扣大模型应用落地这一热点&#xff0c;以“应用即未来——大模型赋能千行百业&#xff0c;新生态拥抱产业未来”为主题&#xff0c;备受社会各界关注。 一、北京已…

STM32点灯闪烁

stm32c8t6引脚图 开发板引脚图 GPIO端口的每个位可以由软件分别配置成 多种模式。 ─ 输入浮空 ─ 输入上拉 ─ 输入下拉 ─ 模拟输入 ─ 开漏输出 ─ 推挽式输出 ─ 推挽式复用功能 ─ 开漏复用功能 配置GPIO端口步骤&#xff1a;开启时钟->使用结构体设置输出模式…

LabVIEW从测试曲线中提取特征值

在LabVIEW中开发用于从测试曲线中提取特征值的功能时&#xff0c;可以考虑以下几点&#xff1a; 数据采集与处理&#xff1a; 确保你能够有效地采集和处理测试曲线数据。这可能涉及使用DAQ模块或其他数据采集设备来获取曲线数据&#xff0c;并在LabVIEW中进行处理和分析。 特…

吉时利KEITHLEY KI-488驱动和说明

吉时利KEITHLEY KI-488驱动和说明

D1.排序

1.快速排序 双指针 采用分治的思想&#xff0c;基于一个数作为标准&#xff0c;进行分治 步骤&#xff1a; 确定分界点的值。x q[l]、q[(lr)/2]、q[r]、随机 都可以&#xff1b;划分区间&#xff1a;使得小于等于x的数放在数组的左边&#xff1b;大于等于x的数放在数组的右边…

系统级别的原生弹窗窗口

<!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>原生的弹出窗口dialog</title><style>…

C语言指针函数指针

跟着这篇文章重新理解了一下&#xff1a;彻底攻克C语言指针 有一个例子感觉可以拿出来看看&#xff1a; char *(*c[10])(int **p); * 这段声明定义了一个长度为10的数组c&#xff0c;数组中的每个元素都是指向函数的指针。每个函数接受一个类型为int **&#xff08;指向指向…

Gitlab Fork Workflow(协作工作流)

Gitlab Fork WorkFlow&#xff08;协作工作流&#xff09; Fork WorkFlow用于团队间的协作开发。在开发过程中&#xff0c;我们都需要将最新修改的代码合并到代码库上&#xff0c;在代码合并之前&#xff0c;为了保证代码符合上传要求&#xff08;符合需求、代码规范等&#xf…

2024/7/7周报

文章目录 摘要Abstract文献阅读题目问题本文贡献问题描述图神经网络Framework实验数据集实验结果 深度学习MAGNN模型相关代码GNN为什么要用GNN&#xff1f;GNN面临挑战 总结 摘要 本周阅读了一篇用于多变量时间序列预测的多尺度自适应图神经网络的文章&#xff0c;多变量时间序…

ASP.NET Core----基础学习03----开发者异常页面 MVC工作原理及实现

文章目录 1. 开发者异常页面(1)Startup.cs 页面的基础配置(2)自定义显示报错代码的前后XX行 2. MVC 的原理3. MVC 的实现4.默认路由路径5.返回Json字符串 1. 开发者异常页面 (1)Startup.cs 页面的基础配置 namespace ASP.Net_Blank {public class Startup{private readonly IC…

Linux muduo 网络库

主要记录示意图和知识点框架&#xff1a; 1、阻塞、非阻塞、同步、异步 在处理IO的时候&#xff0c;阻塞和非阻塞都是同步IO&#xff0c;只有使用了特殊的API才是异步IO。 2、五种IO模型&#xff1a; 阻塞、非阻塞、IO复用、信号驱动、异步IO 3、muduo网络库 muduo网络库给用…

【python】python当当数据分析可视化聚类支持向量机预测(源码+数据集+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

windows 服务器安装svn服务端、迁移svn

svn服务器版本 因为要把旧svn迁移到新的svn&#xff0c;为了保证迁移后的稳定性&#xff0c;安装包使用的旧服务器的svn服务器版本 VisualSVN-Server-3.6.1-x64.msi 安装 配置仓库路径等 其他没截图的就默认配置下一步即可。安装完成先不要启动 迁移 旧的svn服务器直接把…

Windows远程桌面实现之十五:投射浏览器摄像头到xdisp_virt以及再次模拟摄像头(一)

by fanxiushu 2024-07-01 转载或引用请注明原始作者。 本文还是围绕xdisp_virt这个软件展开&#xff0c; 再次模拟成摄像头这个比较好理解&#xff0c;早在很久前&#xff0c;其实xdisp_virt项目中就有摄像头功能&#xff0c; 只是当时是分开的&#xff0c;使用起来…

【SpringBoot】IDEA查看spring bean的依赖关系

前因&#xff1a;在研究springcloud config组件时&#xff0c;我发现config-server包下的EnvironmentController不在扫描的包路径下却可以响应客户端的请求&#xff0c;这吸引了我的注意&#xff0c;我的问题是&#xff1a;EnvironmentController是怎么被添加进bean工厂的。本章…

Golang | Leetcode Golang题解之第218题天际线问题

题目&#xff1a; 题解&#xff1a; type pair struct{ right, height int } type hp []pairfunc (h hp) Len() int { return len(h) } func (h hp) Less(i, j int) bool { return h[i].height > h[j].height } func (h hp) Swap(i, j int) { h[i], h[j]…

26_嵌入式系统网络接口

以太网接口基本原理 IEEE802标准 局域网标准协议工作在物理层和数据链路层&#xff0c;其将数据链路层又划分为两层&#xff0c;从下到上分别为介质访问控制子层(不同的MAC子层&#xff0c;与具体接入的传输介质相关),逻辑链路控制子层(统一的LLC子层&#xff0c;为上层提供统…

CosyVoice多语言、音色和情感控制模型,one-shot零样本语音克隆模型本地部署(Win/Mac),通义实验室开源

近日&#xff0c;阿里通义实验室开源了CosyVoice语音模型&#xff0c;它支持自然语音生成&#xff0c;支持多语言、音色和情感控制&#xff0c;在多语言语音生成、零样本语音生成、跨语言声音合成和指令执行能力方面表现卓越。 CosyVoice采用了总共超15万小时的数据训练&#…

GuitarPro2024音乐软件#创作神器#音乐梦想

嘿&#xff0c;亲爱的朋友们&#xff01;&#x1f44b;&#x1f44b;&#x1f44b;今天我要给你们安利一款超赞的软件——Guitar Pro。这款软件简直是吉他手的福音啊&#xff01;&#x1f389;&#x1f389;&#x1f389; Guitar Pro免费绿色永久安装包下载&#xff1a;&#…