Linux内核定时器Timer的学习

前言

这段时间我会把内核的小模块复习起来并记录成文章给大家发表出来,方便大家来学习,大家感兴趣的话可以点赞关注下,顺便说下想第一时间看我的文章的话可以点击公众号主页右上角有个设为星标,以免错过好文。先从定时器开始学习。

内核定时器简介

定时器是一个很常用的功能,需要周期性处理的工作都要用到定时器, 基本做驱动开发的人都要接触用到的。内核定时器因为采用系统时钟属于软件定时器所以他精度不高,不能作为高精度定时器使用,用法和硬件定时器一样,只不过不需要初始化一大堆寄存器而工作,需要注意一点是默认执行一次就结束了并不是周期性运行的,因此如果要想实现周期性的定时,就需要在定时处理函数中重新开启定时器。

内核定时器的数据结构

Linux内核使用 timer_list 结构体表示内核定时器, timer_list 定义在文件include/linux/timer.h 中

struct timer_list {
         /*
         ¦* All fields that change during normal runtime grouped to the
         ¦* same cacheline
         ¦*/
         struct hlist_node       entry;
         unsigned long           expires; //定时器的超时时间,单位不是时长,单位是节拍数
         void                    (*function)(struct timer_list *);//定时处理函数
         u32                     flags;
         unsigned long           cust_data;//传递给function函数的参数
#ifdef CONFIG_LOCKDEP
         struct lockdep_map      lockdep_map;
#endif
         ...  
 };

timer_list 中有三个重要参数:

  • unsigned long expires; /* 期望定时器要执行的 jiffies 值也就是超时时间,单位是节拍数jiffies */
  • void (*function)(struct timer_list *); / 到达该 jiffies 值时,会调用function定时处理函数/
  • unsigned long data; / 要传递给 function 函数的参数 */

其中 expires 字段表示期望定时器执行的 jiffies 节拍值,到达该 jiffies 值时,将调用 function 函数,并传递 data 作为参数。当一个定时器被注册到内核之后,entry 字段用来连接该定时器到一个内核链表中。

HZ表示一秒的节拍数, 也就是频率。系统的节拍率一般看系统内核宏.config文件里CONFIG_HZ,比如CONFIG_HZ=100意思是1s钟经过100HZ, 100HZ的节拍率的时间精度是10ms。

例如定义一个2s的周期定时器,那么这个定时器期望的超时时间是expires = jffies + 2*HZ / expires = jffies + msecs_to_jiffies(2000)

注意:expires是32位的,因此内核定时器并不适用于长的未来时间点,还有有计数就会溢出的风险,溢出以后会重新从0开始

内核定时器的API函数

del_timer_sync和del_timer的区别: del_timer_sync 不能用在中断上下文中

Linux 内核提供了几个 jiffies 和 ms、us、ns 之间的转换函数

内核定时器的处理流程

1、定义一个定时器

2、编写定时器回调函数(如果需要定时器周期性运行的话就使用 mod_timer)

3、定时器初始化

1、) 初始化定时器

方法一:

DEFINE_TIMER(timer_name, function_name, expires_value, data);

该宏会定义一个名叫 timer_name 内核定时器,并初始化其 name, function, expires 和 base 字段。

方法二:

struct timer_list mytimer; void init_timer(struct timer_list *timer);

上述init_timer函数将初始化struct timer_list的 entry的next 为 NULL ,并为base指针赋值

2、) 设置定时处理函数

void (*function)(struct timer_list *)

3、) 设置超时时间

4、) 设置处理函数的参数(可有可无)

5、) 启动定时器

add_timer用于向Linux内核中注册一个新的定时器,该定时器一旦被注册,定时器就会开始运行。

void add_timer (struct timer_list *timer);

4、删除定时器

del_timer用于删除指定的定时器,不管该定时器是否被激活,都可以被删除。

int del_timer (struct timer_list *timer); 

int del_timer_sync(struct timer_list *timer)

内核定时器demo

例如定时器500ms的demo如下:

   struct timer_list timer;
    /* 定时器回调函数 */
    void timer_function(unsigned long arg)
    {
            printk("timer function callback\n");
     
            mod_timer(&timer, jiffies + msecs_to_jiffies(500));
     }
     
    static int __init timer_init(void)
    {
            /* 1.初始化定时器 */
            init_timer(&timer);
            /* 2.设置定时处理函数 */
            timer.function = timer_function;
            /* 3.设置500ms超时时间 */ 
            timer.expires = jiffies + msecs_to_jiffies(500);
            /* 4.启动定时器 */ 
            add_timer(&timer);
            return 0;
    }
    
    static void __exit timer_exit(void)
    {
            printk("exit\n");
            /* 5.删除定时器 */
            del_timer(&timer);
    
    }
    
    module_init(timer_init);
    module_exit(timer_exit);
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("panxiaoshuai");

结语

相信大家对内核定时器的使用基本有所了解,如果我的文章对你有所收获的话,可以点赞关注转发给你小伙伴们


作者潘小帅, 是一名Linux底层爱好者,不定期写写技术原创文章和分享职场面试文章,徒步,旅游,看电影的爱好,喜欢我的文章可以点赞收藏+关注,感谢你的支持,微信公众号【Linux随笔录】

参考文章:

https://zhuanlan.zhihu.com/p/533792421 https://blog.csdn.net/weixin_45309916/article/details/118584630 https://abcdxyzk.github.io/blog/2013/07/01/kernel-timer/ https://www.cnblogs.com/zhiminyu/p/17628488.html

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

AC/DC电源模块在医疗设备领域的应用探讨

BOSHIDA AC/DC电源模块在医疗设备领域的应用探讨 AC/DC电源模块是一种将交流电转换为直流电的设备,广泛应用于各种电子设备中。在医疗设备领域,AC/DC电源模块的应用具有重要意义。本文将探讨AC/DC电源模块在医疗设备中的应用,并分析其优势和…

【mysql】mysql单表查询、多表查询、分组查询、子查询等案例详细解析

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…

【web网页制作】html+css旅游家乡河南开封主题网页制作(4页面)【附源码】

HTMLCSS家乡河南主题网页目录 🍔涉及知识🥤写在前面🍧一、网页主题🌳二、页面效果Page1 首页Page2 开封游玩Page 3 开封美食Page4 留言 🌈 三、网页架构与技术3.1 脑海构思3.2 整体布局3.3 技术说明书 🐋四…

SpringBoot启动时自动执行方法的方式

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 在springBoot中我们…

[华为OD]C卷 运输时间 200 动态规划

题目: M辆车需要在一条不能超车的单行道到达终点,起点到终点的距离为N。速度快的车追上前车 后,只能以前车的速度继续行驶,求最后一车辆到达目的地花费的时间。 注意: 每辆车固定间隔1小时出发,比如第…

antd vue pro (vue 2.x) 多页签详细操作

antd vue pro 多页签配置操作,具体操作如下。 1.引入 tagviews文件 在 store/modules 中创建 tagviews.js ,复制一下代码到文件中保存 const state {visitedViews: [],cachedViews: [] }const mutations {ADD_VISITED_VIEW: (state, view) > {if …

三、Redis五种常用数据结构-Hash

Hash是redis中常用的一种无序数据结构。结构类似HashMap。 具体结构如下:key field value 1、优缺点 1.1、优点 同类数据归类整合储存,方便数据管理。相比于string操作消耗内存和CPU更小。分字段存储,节省网络流量。 1.2、缺点 过期时间…

盘点一下近年来常用的电脑监控软件

企业电脑监控软件通常用于监视员工在工作时间内的电脑使用情况,以确保他们的工作效率和安全性。以下是几种常见的企业电脑监控软件: 1、Ping32 Ping32是一款集成多功能的企业级电脑监控软件,包括员工上网行为管理、文件外发审计、屏幕活动监…

Milvus Cloud 的RAG 的广泛应用及其独特优势

一个典型的 RAG 框架可以分为检索器(Retriever)和生成器(Generator)两块,检索过程包括为数据(如 Documents)做切分、嵌入向量(Embedding)、并构建索引(Chunks Vectors),再通过向量检索以召回相关结果,而生成过程则是利用基于检索结果(Context)增强的 Prompt 来激…

使用API有效率地管理Dynadot域名,设置所有域名默认whois信息

关于Dynadot Dynadot是通过ICANN认证的域名注册商,自2002年成立以来,服务于全球108个国家和地区的客户,为数以万计的客户提供简洁,优惠,安全的域名注册以及管理服务。 Dynadot平台操作教程索引(包括域名邮…

WordPress与Joomla有哪些差异

在前不久遇到Hostease的客户在咨询WordPress和Joomla要如何选择。他们之间有哪些区别。Hostease提供的虚拟主机都可以直接安装这2个网站程序。下面针对WordPress和Joomla进行一些分析和比较。 WordPress和Joomla都是流行的内容管理系统(CMS),…

2024年51cto下载的视频怎么导出

如果你喜欢在51cto上观看各种专业技术视频,那么你可能想将喜欢的视频保存到本地设备中,以便随时随地观看。今天,我们就来探讨一下如何在2024年将51cto下载的视频导出到你的设备中 下载51cto的工具我已经打包好了,有需要的自己下载…

AI换脸原理(4)——人脸对齐(关键点检测)参考文献2DFAN:代码解析

注意,本文属于人脸关键点检测步骤的论文,虽然也在人脸对齐的范畴下。 1、介绍 在本文中,重点介绍了以下几项创新性的成果,旨在为人脸关键点检测领域带来新的突破。 首先,成功构建了一个卓越的2D人脸关键点检测基线模型。这一模型不仅集成了目前最优的关键点检测网络结构,…

信息熵为凹函数-推导

凹函数和凸函数,是凹凸是相对于x轴来说的,对于熵来说,它是凹函数。因为它是-log函数,函数曲线相对于x轴来说是凸的。 Jensen不等式推导 以下是证明熵是凹函数。 引理: ①Jensen不等式,条件:…

SpringBoot框架如何接入RocketMQ?

目录 一、SpringBoot框架介绍 二、RocketMQ介绍 三、RocketMQ的应用场景 四、SpringBoot框架如何接入RocketMQ 一、SpringBoot框架介绍 Spring Boot是一个开源的Java框架,它基于Spring框架,旨在简化Java应用程序的开发。Spring Boot通过自动化配置和约定优于配置的原则,大…

谷歌开源!用 js 编写 Shell 脚本! | 开源日报 No.247

google/zx Stars: 41.4k License: Apache-2.0 zx 是一个用于编写更好脚本的工具。 提供有用的包装器,简化了对 child_process 的操作转义参数并提供合理的默认值使用 JavaScript 编写复杂脚本时比 Bash 更方便可以直接使用 npm 安装 dani-garcia/vaultwarden St…

评估Transitions

Stateflow使用图表中的转换从一种OR状态移动到另一种OR状态。对于图表执行的输入和执行工作流,Stateflow评估转换以确定它们是否有效。有效转换是条件标签为true且路径以状态结束的转换。如果转换有效,则Stateflow将从源状态退出并进入目标状态。 评估Transitions的工作流 T…

图搜索算法 - 拓扑排序

相关文章: 数据结构–图的概念 图搜索算法 - 深度优先搜索法(DFS) 图搜索算法 - 广度优先搜索法(BFS) 拓扑排序 概念 几乎所有的工程都可分为若干个称作活动的子工程,而这些子工程之间,通常受…

Debug项目失败Run成功

一:问题 idea中启动服务,服务一直在启动中,最后超时启动失败 重新构建项目也是一样 二:个人分析 debug因为断点太多了项目起不起来,试一下run直接运行,项目可以快速启动 三:解决办法 在控制…

四、Redis五种常用数据类型-List

List是Redis中的列表,按照插入顺序保存数据,插入顺序是什么样的,数据就怎么保存。可以添加一个元素到列表的头部(左边)或者尾部(右边)。一个列表最多可以包含232-1个元素(4294967295,每个列表超过40亿个元素)。是一种双向列表结构…