当前位置: 首页 > ds >正文

驱动-Linux定时-timer_list

了解内核定时相关基础知识

文章目录

  • 简要介绍
  • timer_list 特点
  • API 函数
  • 实验
    • 测试程序 - timer_mod.c
    • 编译文件-Makefile
    • 实验验证
  • 注意事项
  • 总结


简要介绍

硬件为内核提供了一个系统定时器来计算流逝的时间(即基于未来时间点的计时方式, 以当前时刻为计时开始的起点, 以未来的某一时刻为计时的终点) , 内核只有在系统定时器的帮助下才能计算和管理时间, 但是内核定时器的精度并不高, 所以不能作为高精度定时器使用。并且内核定时器的运行没有周期性, 到达计时终点后会自动关闭。 如果要实现周期性定时, 就要在定时处理函数中重新开启定时器。

Linux 内核中使用 timer_list 结构体表示内核定时器, 该结构体定义在“内核源码/include/li
nux/timer.h”文件中, 具体内容如下所示


struct timer_list {struct hlist_node   entry;unsigned long       expires;/* 定时器超时时间,单位是节拍数 */void            (*function)(struct timer_list *);/* 定时处理函数 */u32         flags;#ifdef CONFIG_LOCKDEPstruct lockdep_map  lockdep_map;
#endifANDROID_KABI_RESERVE(1);ANDROID_KABI_RESERVE(2);
};

timer_list 特点

inux 内核定时器是基于 timer_list 结构的动态定时器,具有以下特点:

  • 不是周期性的,超时后会自动失效

  • 基于内核的 jiffies 计时

  • 在中断上下文执行,因此不能睡眠

  • 精度取决于 HZ 值(通常为 1ms 或 10ms)

API 函数

函数作用
void add_timer(struct timer_list *timer)向 Linux 内核注册定时器,使用 add_timer 函数向内核注册定时器以后,定时器就会开始运行
int del_timer(struct timer_list * timer)删除一个定时器
int mod_timer(struct timer_list *timer,unsigned long expires)修改定时值,如果定时器还没有激活的话,mod_timer 函数会激活定时器

在使用add_timer()函数向 Linux 内核注册定时器之前,还需要设置定时时间,定时时间由timer_list结构体中的expires参数所确定,单位为节拍数

这里简要理解,节拍数 jiffies 和 时间之间的转换函数:

jiffies_64用于64位系统,而jiffies用于 32 位系统。为了方便开发,Linux 内核还提供了几个jiffies和ms、us、ns之间的转换函数,如下 所示:

函数作用
int jiffies_to_msecs(const unsigned long j)将 jiffies 类型的参数 j 分别转换为对应的毫秒
int jiffies_to_usecs(const unsigned long j)将 jiffies 类型的参数 j 分别转换为对应的微秒
u64 jiffies_to_nsecs(const unsigned long j)将 jiffies 类型的参数 j 分别转换为对应的纳秒
long msecs_to_jiffies(const unsigned int m)将毫秒转换为 jiffies 类型
long usecs_to_jiffies(const unsigned int u)将微秒转换为 jiffies 类型
unsigned long nsecs_to_jiffies(u64 n)将纳秒转换为 jiffies 类型

既然要定时,那么情形就是 把定时时间转换成节拍数,系统内核根据节拍数和节拍频率。内核里面只认节拍数,它对应的就是频率

例如:进行3秒钟的定时:

timer_test.expires = jiffies_64 +msecs_to_jiffies(3000)

实验

测试程序 - timer_mod.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>static void function_test(struct timer_list  *t);//定义function_test定时功能的函数
DEFINE_TIMER(timer_test,function_test);static void function_test(struct timer_list *t){printk(" this is function test \n");mod_timer(&timer_test,jiffies_64+msecs_to_jiffies(5000));  使用mod_timer函数将定时时间设置为五秒后}static int __init time_module_init(void) //驱动入口函数
{timer_test.expires = jiffies_64 + msecs_to_jiffies(5000);//将定时时间设置为五秒后add_timer(&timer_test);//添加一个定时器return 0;}
static void __exit time_module_exit(void) //驱动出口函数
{del_timer(&timer_test);//删除一个定时器printk("module exit \n");}
module_init(time_module_init);
module_exit(time_module_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("wang fang chen");

源码分析

  • 这里用到了定时器timer_list 的三个api 函数:
    定义定时器:DEFINE_TIMER(timer_test,function_test); 参数为定时器名称和回调方法
    添加定时器:add_timer(&timer_test);
    修改定时器:mod_timer(&timer_test,jiffies_64+msecs_to_jiffies(5000));
    删除定时器:del_timer(&timer_test);

    **注意点:**定时器的名称并不是作为变量定义的,作为方法参数定义了的 DEFINE_TIMER的方法参数。
    回调函数 function_test 是先定义,然后实现 。

编译文件-Makefile

#!/bin/bash
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
obj-m += timer_mod.o
KDIR :=/home/wfc123/Linux/rk356x_linux/kernel
PWD ?= $(shell pwd)
all:make -C $(KDIR) M=$(PWD) modulesclean:make -C $(KDIR) M=$(PWD) clean

实验验证

加载驱动看打印信息
在这里插入图片描述

注意事项

  • 定时器精度:内核定时器的精度受 HZ 值影响,不适合需要高精度的场合

  • 执行上下文:回调函数在中断上下文执行,不能调用可能睡眠的函数

  • 多核处理:del_timer() 可能在 SMP 系统上返回后定时器仍在运行,使用 del_timer_sync() 更安全

  • 竞争条件:确保在模块退出时删除所有定时器

总结

这里了解的是内核的一个定时器timer_list 的使用。 了解基本知识即可。

http://www.xdnf.cn/news/6550.html

相关文章:

  • ollama 重命名模型
  • 每日一道leetcode(新学数据结构版)
  • CISA 备考通关经验及回忆题分享
  • 1:OpenCV—图像基础
  • python打卡day26
  • 【开源Agent框架】OWL:面向现实任务自动化的多智能体协作框架深度解析
  • 从代码学习深度学习 - 风格迁移 PyTorch版
  • 中国科学院计算所:从 NFS 到 JuiceFS,大模型训推平台存储演进之路
  • 【知识点】大模型面试题汇总(持续更新)
  • SQLPub:一个提供AI助手的免费MySQL数据库服务
  • 智慧化系统安全分析报告
  • AI学习博文链接
  • 12V升24V升压恒压WT3207
  • YOLO格式数据集制作以及训练
  • c++多态面试题之(析构函数与虚函数)
  • 工业操作系统核心技术揭秘
  • sizeof()运算符
  • 嵌入式学习笔记 D21:双向链表的基本操作
  • 系统集成项目管理工程师学习笔记
  • 【日撸 Java 三百行】Day 16(递归)
  • Ubnutu ADB 无法识别设备的解决方法
  • 数据库的锁 - 全局锁、表锁、行锁
  • Vuex和Vue的区别
  • RabbitMQ概述
  • 【ArcGIS技巧】根据地块、界址点图层生成界址线
  • 如何在Edge浏览器里-安装梦精灵AI提示词管理工具
  • MySQL数据类型之VARCHAR和CHAR使用详解
  • 基于大模型预测围术期麻醉苏醒时间的技术方案
  • Ubuntu 安装 Redis
  • 《Adversarial Sticker: A Stealthy Attack Method in the Physical World》论文分享(侵删)