Linux内核定时器

带你走进linux 内核 定时器(timer)实现机制 定时器层是基于tick层(高精度定时器)之上的,是根据系统jiffies来触发的,精度相对比较低。利用定时器,我们可以设定在未来的某一时刻,触发一个特定的事件。经常,也会把这种低精度定时器称作时间轮(Timer Wheel)。在内核中,一个定时器是使用 timer_list 结构体来表示的: entry:所有的定时器都会根据到期的时间被分配到一组链表中的一个中,该字段是链表的节点成员。 expires:字段指出了该定时器的到期时刻,也就是期望定时器到期时刻的jiffies计数值。这是一个绝对值,不 阅读详情

一、内核时间的相关概念

1. 墙上时钟:也就是实际时间。

2. 系统时间:自系统启动开始所经过的时间。

3. 时钟中断:内核会周期性的产生时钟中断,在中断处理函数中执行一些与时间相关的操作,如更新时间,进程调度,检查时间片等。

4. 节拍率:在linux内核中,通过编程定义节拍率,也就是HZ。每1/HZ秒发生一次时钟中断。在ARM中,节拍率被定义为100,节拍率越大,系统进入时钟中断就越频繁,时间和进程调度等操作就越准确,但对系统的负担也就越大。
HZ在Linux内核源码目录下的arch/arm/include/asm/param.h定义:
#ifdef __KERNEL__
#define HZ CONFIG_HZ /* Internal kernel timer frequency */
#define USER_HZ 100 /* User interfaces are in "ticks" */
#define CLOCKS_PER_SEC (USER_HZ) /* like times() */
#else
#define HZ 100
#endif
可见,内核空间的HZ由__KERNEL__和CONFIG_HZ决定,而CONFIG_HZ在.config(选择编译选项后产生的配置文件)中定义,如在顶层目录下的.config有如下定义:CONFIG_HZ=256。
HZ在内核的源代码中是一个全局常量可以修改,但是一旦内核编译成镜像文件时,HZ就是一个常量了。HZ的值一般在10~1000之间。HZ越大,系统计时越精确,系统的实时性越好,但是系统的负担就会重。一般CPU的主频越高,HZ越的值越大。

5. jiffies:32位的全局变量,用来记录自系统启动以来产生的节拍的总数。系统启动时清零,每次时钟中断加一。所以,一秒内的时钟中断次数(即jiffies一秒内增加的值)也就等于HZ。如果系统时间以秒来表示,那就等于jiffies/HZ秒。

6. 实时时钟(RTC):体系结构中用于维持系统时间的设备,就像电脑的BIOS,需要在关机状态时通过电池供电。系统启动时通过读取RTC
来初始化墙上时钟


二、Linux内核定时器

2.1 定义及初始化一个定时器结构体timer_list
timer_list在Linux内核源码目录下include/linux/timer.h下定义:
struct timer_list {
/*
* All fields that change during normal runtime grouped to the
* same cacheline
*/
struct list_head entry;
unsigned long expires;
struct tvec_base *base;


void (*function)(unsigned long);
unsigned long data;


int slack;


#ifdef CONFIG_TIMER_STATS
void *start_site;
char start_comm[16];
int start_pid;
#endif
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};

关键成员说明:
.expires:定时器超时处理函数的超时时间
.function:定时器超时处理函数
.data:定时器超时处理函数的参数

这三个成员是由用户设置,其余一般由内核处理


此外,还有一个关于定时器结构体的宏定义,在Linux内核源码目录下include/linux/timer.h下定义:
#define DEFINE_TIMER(_name, _function, _expires, _data) \
struct timer_list _name = \
TIMER_INITIALIZER(_function, _expires, _data)

2.1.1 直接定义一个定时器结构体,如:
struct timer_list timer;

2.1.2 使用宏定义一个定时器结构体,如:
DEFINE_TIMER(timer, timer_func,100);

2.2 设置超时时间,定义定时器处理函数和传参
指定timer的expires、function和data。

2.2.1 给结构体成员分别赋值或,如:
void timer_func(unsigned long data)
{

}

static int __init timer_dev_init(void)
{
timer.funciton = timer_func;
timer.expires = jiffies+5*HZ;
timer.data = 100;
}

2.3 使用init_timer()完成全部初始化;
函数原型:int init_timer(struct timer_list *timer);
参数说明:
timer: 定时器结构体变量地址
返回值:
成功返回0,失败返回一个负的错误码。

如:init_timer(&timer);


2.4 激活定时器
激活定时器使用add_timer();
函数原型:int add_timer(struct timer_list *timer);
参数说明:
timer: 定时器结构体变量地址
返回值:
成功返回0,失败返回一个负的错误码。

如:add_timer(&timer);

当调用add_timer后,就会将定时器交由内核来管理,当时间一到,内核调用进程/*swapper*/来执行处理函数,因此,若设置了重复执行,当rmmod驱动(若没有删除定时器)后,定时器超时处理函数会继续执行,定时器激活后,它只会在指定时间执行一次处理函数,执行后会将定时器在内核中移除。

2.5 修改定时器
如果要实现隔指定时间又重复执行,可使用如下方法:

2.5.1 在定时器处理函数中添加如下代码,即再次激活定时器。
timer.expires = jiffies+5*HZ;
add_timer(&timer);

2.5.2 在定时器处理函数中使用mod_timer();
这是改变定时器超时时间的函数,如果在指定的定时器(timer)没超时前调用,超时时间会更新为新的新的超时时间(expires)。
如果在定时器超时后调用,那就相当于重新指定超时时间并再次激活定时器。

函数原型:int mod_timer(struct timer_list *timer, unsigned long expires);
参数说明:
timer: 定时器结构体变量地址
expires:定时时间
返回值:
成功返回0,失败返回一个负的错误码。

如:mod_timer(&timer, jiffies+5*HZ);

2.6 删除定时器
若想在定时器没有超时前取消定时器,则使用del_timer();
函数原型:void del_timer(struct timer_list *timer);
参数说明:
timer: 定时器结构体变量地址
返回值:
无返回值。

如:del_timer(&timer);


三、Linux内核定时器实例

驱动程序(timer_dev.c):

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timer.h>	
#include <linux/sched.h>	//current->comm

//1. 定义一个定时器结构体
static struct timer_list timer;

void timer_func(unsigned long data)
{
	printk("data:%lu\n", data);
	printk("jiffies:%lu\n", jiffies);
	printk("current.comm:%s\n", current->comm);
	
	//修改定时器
	mod_timer(&timer, jiffies+2*HZ);
}

static int __init timer_dev_init(void)
{
	//2. 设置超时时间,定义定时器处理函数和传参
	timer.expires = jiffies+5*HZ;
	timer.function = timer_func;
	timer.data = 100;
	
	//3. 初始化定时器结构体
	init_timer(&timer);
	
	//4. 激活定时器
	add_timer(&timer);
	
	printk("timer_dev init\n");
	printk("current.comm:%s\n", current->comm);
	
	return 0;
	
}

static void __exit timer_dev_exit(void)
{
	//删除定时器
	del_timer(&timer);
	
	printk("timer_dev exit\n");
}

module_init(timer_dev_init); 
module_exit(timer_dev_exit); 
MODULE_LICENSE("GPL");

编译文件(Makefile):

obj-m += timer_dev.o 
KERN_DIR=/home/gec/linux-2.6.35.7-gec-v3.0-gt110

modules:
	$(MAKE) -C $(KERN_DIR) M=$(PWD) modules
clean:
	$(MAKE) -C $(KERN_DIR) M=$(PWD) modules clean


【Linux】内核定时器 介绍Linux内核中的定时器以及如何使用 阅读详情

相关推荐

Linux 内核定时器实验

Linux 内核中有大量的函数需要时间管理,比如周期性的调度程序、延时程序、对于驱动编写者来说最常用的就是定时器。硬件定时器提供时钟源,时钟源的频率可以设置, 设置好以后就周期性的产生定时中断,系统使用定时中断来计时。中断周期性产生的频率就是系统频率,也叫做节拍率(tick rate)(有的资料也叫系统频率)。其中jiffies_64用于64为系统,jiffies用于32位系统。为了硬件的兼容性他们的关系如下:其实读取jiffies变量也就是读取jiffies_64的低32位。

m0_69211839的博客 918

Linux之内核定时器

当 jiffies 变量的值超过它的最大存放范围后就会发生溢出, 对于 32 位无符号长整型, 最大取值为 2^32-1,在溢出前, 定时器节拍计数最大为 4294967295, 如果节拍数达到了最大值后还要继续增加的话, 它的值会。jiffies 变量总是无符号长整型(unsigned long), 因此, 在 32 位体系结构上是 32 位, 在时钟频率为 100的情况下, 497 天后会溢出, 如果频率是 1000, 49.7 天后会溢出。相对于事件驱动, 内核中有大量的函数都是基于时间驱动的。

风间琉璃的博客 2379

Linux内核编程(九)Linux内核定时器

Linux内核中有一个宏HZ,这个宏用来表示一秒钟对应的节拍的数量。利用Linux内核中的这个宏,我们就可以把时间转换成节拍数。比如,定时一秒钟换成节拍数就是expires=jiffies+1*HZ,其中宏定义jiffies为系统当前时间对应的节拍数。宏HZ的值我们是可以设置的,也就是说一秒钟对应多少个节拍数我们是可以设置的。打开make menuconfig图形化配置界面进行设置,具体设置路径查看其它博客。

qq_1033275663的博客 2309

linux内核定时器

本文介绍了linux内核中的两种定时器,包括传统jiffies定时器和搞定度hrtimer定时器,介绍了两种定时器的创建、修改、删除等使用方法。介绍了如何使用两种定时器设置周期性任务。

qq_28499879的博客 2165

【Linux驱动编程】如何使用内核定时器

linux内核定时器是内核用于控制在未来某个时间点或者特定时间段内调度执行某个函数的一种机制。

只要思想不滑坡,想法总比问题多。 1602

深入博通PEX89000内部:那颗ARM CPU和Synthetic Mode到底能玩出什么花样?

本文深入解析博通PEX89000系列PCIe交换芯片内置的ARM CPU与Synthetic Mode技术,揭示其在AI计算和数据中心的智能潜能。通过ARM Cortex CPU的实时控制和Synthetic Mode的自治网络功能,PEX89000实现了GPU集群的动态拓扑重组和资源池化,大幅提升AI训练效率。文章还探讨了该技术在软件定义数据平面和弹性AI架构中的创新应用。

weixin_30776273的博客 212

16 Linux 内核定时器

一般周期性的工作都是用到了定时器,Linux 内核定时器采用系统时钟来实现。Linux 内核定时器只要给出超时时间(定时值)和定时器处理函数。当超时时间到了,设置的定时函数就会执行。需要注意的是,内核定时器不是周期性的,它是运行完就自动关闭,如果想要周期性运行定时器,那么需要在定时处理函数中重新开启定时器。/**//* 定时器超时时间,单位是节拍数 *//* 定时处理函数*/u32 flags;/* 标志位 */#endif。

Toutiegongzhu的博客 1397

【超详细】C#的单例模式

本文详细介绍了C#中的单例设计模式,包括两种实现方式:普通类泛型单例(Singleton<T>)和基于MonoBehaviour的组件单例(MonoSingleton<T>)。单例模式通过私有构造、静态私有实例和公共访问入口确保全局唯一实例,具有节省资源、保证数据一致性等优势。文章分别阐述了两者的核心原理、代码实现、使用场景及注意事项,并提供了日志管理器和音效管理器的具体应用示例。特别强调了多线程安全、初始化时机和避免过度使用等重要原则,为Unity开发中合理运用单例模式提供了全面指导。

grapefruit_lyy的博客 1534

Linux驱动学习—内核定时器

比如,现在是10点5分,我要定时5分钟,那么定时就是10点5分+5分钟=10点10分。HZ的值我们是可以设置的,也就是一秒对应的时钟拍数我们是可以设置的,Linux内核会使用CONFIG_HZ来设置自己的系统时钟。宏HZ就是CONFIG_HZ,因此HZ=100,表示一秒的节拍数是100,在编译Linux内核的时候可以通过图形化界面设置系统节拍率,按照如下路径打开配置界面。通过上图我们可以发现可选的系统节拍率为100HZ,200HZ,250HZ,300HZ、500HZ和1000HZ.默认是100HZ。

suifen_的博客 2337

A-Level CS 计算机科学 考试知识点——考试介绍&第1章

前言:该系列文章是本人在给学生辅导本课程的过程中结合英文教材所总结的,该系列共分为30章,主要介绍了考试的核心知识点。若需要A-Level CS 计算机科学考试辅导也可以私信我。 目录 关于A-Level CS 计算机科学考试 考试简介 考试内容 考试时间 评分情况 第1章 信息表示 本章学习内容 1.01 数字系统 1.02 数字的内部编码 整数编码(Coding for integers) 二进制编码的十进制(Binary coded decimal——BCD) 1.03.

王俊的博客 6458

告别上位机!用MCGS触摸屏+FTP服务器,5分钟搞定工控机文件自动同步

本文介绍了一种工业自动化领域的高效解决方案,通过MCGS触摸屏结合FTP服务器实现工控机文件的自动同步,无需开发上位机软件。该方案特别适用于图像采集、参数同步、数据备份等场景,具有成本低、可靠性高、维护简便等优势。详细配置指南和实战案例帮助用户快速实现零代码文件同步。

weixin_30872499的博客 560

如何使用 Linux 内核定时器

内核定时器

安迪西_嵌入式攻城狮 1482

舵机操作手册

微型伺服马达原理与控制(中鸣) 1、微型伺服马达内部结构一个微型伺服马达内部包括了一个小型直流马达;一组变速齿轮组;一个反馈可调电位器;及一块电子控制板。其中,高速转动的直流马达提供了原始动力,带动变速(减速)齿轮组,使之产生高扭力的输出,齿轮组的变速比愈大,伺服马达的输出扭力也愈大,也就是说越能承受更大的重量,但转动的速度也愈低。 2、微行伺服马达的工作原理一个微型伺服马达是一个典型闭环反馈系统,其原理可由下图表示: 减速齿轮组由马达驱动,其终端(输出端)带动一个线性的比例电位器作位置检测,该电位器把

HEIMENGER的博客 3137

【Linux】Linux5.4.70内核定时器的使用

文章目录1. 定时器简介2. Timer相关API介绍3. Timer时间单位4. Timer Demo测试验证5. 定时器内部机制简单分析6. 参考资料 1. 定时器简介 本篇文章介绍内核定时器是基于内核Linux5.4.70版本,它是内核用来控制再未来某个时间点(基于jiffies)调度执行某个函数的一种机制,代码实现位于include/linux/timer.h和kernel/time/timer.c文件中。 定时器数据结构,如下: struct timer_list { /* * All fi

ZHONGCAI0901的博客 7757

【WLAN】【调试】再谈如何使用Wireshark解密WiFi数据包——使用TK信息

- 本文介绍了一种wireshark使用TK信息解密空口报文的方式,该方式对是否有关联过程的报文没有要求。

一介草民,只为生活。 1188

RK3568驱动 SPI主/从 配置

RK3568 SPI 配置指南 内核配置:启用用户空间驱动(主)和从模式协议支持。 主模式:设备树设置status="okay"、max-freq及引脚复用,子节点compatible="rockchip,spidev"。 从模式:需添加spi-slave属性,子节点命名以slave@X开头。 编译烧写:修改设备树后编译内核或全量镜像,验证/dev/spidevX.Y节点。 测试:使用spidev_test工具,主模式可环回测试,从模式需与主设备通信。 (关键:从模式强制spi-slave和命名规则,频率匹

文石_2009的博客 1146

Linux下内核定时器

不同于单片机定时器,Linux内核定时器是一种基于未来时间点的计时方式,它以当前时刻为启动的时间点,以未来的某一时刻为终止点,类似于我们的闹钟。内核定时器的精度不高,不能作为高精度定时器使用,其内核定时器不是周期性运行的,超时以后就会自动关闭,因此要想实现周期性的定时,就需要在定时处理函数中重新开启定时器。

西岸贤 2402

多源异构数据在线可视化ETL编排平台深度实践:基于Python与Apache Calcite的现代数据管道构建

在当今企业数据环境中,数据源呈现爆发式增长与高度异构性。传统ETL工具面对多源(MySQL、PostgreSQL、MongoDB、Hive、文件系统等)与异构(结构化、半结构化、非结构化)数据时,往往面临扩展性差、学习曲线陡峭、难以融入现代DevOps体系等问题。本文深入探讨了如何构建一个基于Python/Pandas、Apache Calcite(通过JPype桥接)以及Vue.js前端的轻量级、在线可视化ETL编排平台。

2201_76125261的博客 77

linux内核定时器的使用

文章目录时钟源系统节拍设置jiffies和时间之间的转换函数内核定时器一般使用流程其它相关函数 时钟源 应该是generic timer,百度吧 系统节拍设置 比如我想定时3s钟,那么就是3*HZ即可。 Linux 内核使用全局变量 jiffies 来记录系统从启动以来的系统节拍数,系统启动的时候会将 jiffies 初始化为 0,jiffies 定义在文件 include/linux/jiffies.h 中,定义如下: extern u64 __jiffy_data jiffies_64; /* 用

weixin_44360592的博客 754

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

上一篇: 混杂设备驱动模型设计LED驱动
下一篇: TCP和UDP的区别
SLASH_24
博客等级 码龄10年 7粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值