0

0

高精度定时器的相关介绍及操作框架解析

WBOY

WBOY

发布时间:2024-07-20 09:16:08

|

529人浏览过

|

来源于ITcool

转载

突兀地说高精度定时器,觉得摸不着脑子,起码初学者会沮丧,而且从字面上来理解,很简单,定时器嘛,精度低点,之后,就没有之后了。虽然差不多就是那么回事,只是上面涉及到了一些别的细节上的问题。

工欲善其事必先利其器,在开始讲之前,我们先利一下器:

2相关的用到的几个源代码文件以及其路径如下:

Hrtimers.txt(linux-3.2.12documentationtimers)

Hrtimer.c(linux-3.2.12kernel)

Hrtimer.h(linux-3.2.12includelinux)

2单纯的在高精度定时器模式下操作高精度定时器,整个操作框架如下:

初始化hrtimer_init,通过hetimer结构体设置相关数据,例如定时时长等->开启定时器hrtimer_start->运列宽精度定时器hrtimer_run_queues->触发中断,调用中断反弹函数,hrtimer_interrupt->移除高精度定时器remove_hrtimer.

读者现今脑袋里有一个框架,具体驱动细节下文将一一论述。

先概述一下,可能会有些拗口的东西在上面难理解,不要紧,旁边会有相关的代码和事例来解释。

?高精度定时器根据时间在一棵黑红树上排序。

?她们独立于周期时钟linux 应用定时器,采用脉宽时间戳而非jiffies的时间尺寸。

先把Linux代码上面的高精度定时器相关的文档掏出来,瞧瞧他的介绍,之后我再解释一下,文档路径:Hrtimers.txt(linux-3.2.12documentationtimers)

文档内容……说实话文档有点长,但是Linux的文档维护度不是很高,我从上面找了几句话翻译下来,之后解释一下:

?Thispatchintroducesanewsubsystemforhigh-resolutionkerneltimers.这句话里的patch这个词组有点意思,他是说高精度定时器作为一个补丁包被安装到系统里的,在2.6.16之前是没有这个概念的。

?第二点,英语太长就不贴了,是说为何要用高精度定时器,由于每位系统都存在定时器,其实精度不高,相比较而言就称之为低精度定时器。说白了就是须要高精度。

?第三点,高精度定时器还有个特征,就是他的框架在编译的时侯是在内核里,而且假如没有配置高精度定时器,这么高精度定时器是根据普通的定时器来运行。

?最后一点,高精度定时器是采用黑红树算法实现的,而普通的定时器是采用时间轮循算法实现的.

?另外,文档中还解释了好多诸如时钟源、数据结构、红黑树等等问题,这种问题在下边分开论述。

应用定时器程序-1PLC_linux 应用定时器_应用定时器2

一、相关的数据结构

高帧率定时器所涉及的数据结构,我们从这几大方面考虑:

关于来源:就是说这个时钟是如何来的,在hrtimer.h中定义了一个结构体,代码如下:

structhrtimer_clock_base{

structhrtimer_cpu_base*cpu_base;

intindex;//用于区分时钟的属性(一共有两种,下边将会提到)

clockid_tclockid;//每位CPU所支持的时钟的ID

structtimerqueue_headactive;//正在启用的定时器的黑红树枝节点

ktime_tresolution;//时钟的帧率,毫秒

ktime_t(*get_time)(void);//拿来恢复当前时钟

ktime_tsoftirq_time;//在软中断中运列宽精度定时器队列的时间

ktime_toffset;//更改定时器时钟的额偏斜量

};

关于前面的几个元素,,有些东西解释一下。

高帧率定时器可以基于两种时钟(时钟基础,clockbase):一种是单调时钟(CLOCK_MONOTONIC),在系统启动时linux是什么系统,从0开始;另一种时钟(CLOCK_REALTIME)表示系统的实际时间。上文的结构体structhrtimer_clock_base中,index元素就是拿来分辨是CLOCK_MONOTONIC还是CLOCK_REALTIME时钟的。对于系统的每一个CPU都提供了一个包含这两种时钟基础的数据结构,每一个时侯总时钟基础都有一个黑红树,来排序所有待决的高精度定时器linux 应用定时器,而每位CPU都提供两个时钟基础(单调时钟和实际时间),所有定时器都按过期时间在黑红树上排序,假如定时器早已到期但其处理程序反弹函数仍未执行,则从黑红树迁移到一个数组中。在调整实时时钟的时侯,会导致储存在CLOCK_REALTIME时钟基础上的定时器的过期时间值与当前实际时间之间的误差。offset数组有助于修正这些情况,他表示定时器须要校准的偏斜量。因为这只是一种临时效应,极少发生。

在认识时钟源之前linux软件下载,我们或许还应当认识一个结构体structhrtimer,代码如下:

structhrtimer{

structtimerqueue_nodenode;//定时器队列节点,同时还管理node.expires,高精度定时器的绝对失效时间在其内部的算法这个时间和定时器基于的时钟有关(就是上文说的那两种时基).

应用定时器2_linux 应用定时器_应用定时器程序-1PLC

ktime_t_softexpires;//绝对的最早的到期时间

enumhrtimer_restart(*)(structhrtimer*);//定时器到期反弹函数

structhrtimer_clock_base*base;//指向时基的表针(每位CPU,每位时钟)

unsignedlongstate;//状态信息,用来看位值

#ifdefCONFIG_TIMER_STATS

intstart_pid;//定时器统计区域储存的开始计时的任务的pid

void*start_site;//定时器储存当前定时的开始值

charstart_comm[16];//定时器统计区域名称开始计时的储存过程

#endif

};

以上这个结构体,对于用户来说,只需关心三点,第一是数组,这个是定时器失效后的反弹函数,第二是expires,这个表示到期时间,第三是最后一句话,高精度定时器结构体的使用必须经过hrtimer_init()函数的初始化,hrtimer_init()函数属于应用插口,所以放到前面说。这儿还有一个问题,也是高精度定时器的核心的问题,就是黑红树在高精度定时器的应用问题,其实现今讲这个有点早,而且先让读者心中有那么个底,Linux的传统定时器通过时间轮算法实现(timer.c),但hrtimer通过黑红树算法实现。在structhrtimer上面有一个node域,类型为structtimerqueue_node,这个域代表了hrtimer在黑红树中的位置,注意一下,我参考的源代码是3.2.12版本,在2.6.X版本中这个域的格式为structrb_node。这儿先跟读者打声招呼,有那么回事,等在将具体用法时,我们在谈谈是怎样实现的。

两个重要的结构体说完了,因为要兼容多核处理器,因而会涉及到每位CPU的时基,结构体structhrtimer_cpu_base就是拿来定义每位CPU的时钟的,目前每位CPU只对应于单调时钟和实时时钟,结构体如下:

structhrtimer_cpu_base{//单个CPU时基结构体

raw_spinlock_tlock;//锁定相关的时基和定时器,载流子锁

unsignedlongactive_bases;//用活动的定时器标记基础的位数组

#ifdefCONFIG_HIGH_RES_TIMERS

ktime_texpires_next;//即将到期的下一个时间的绝对时间

inthres_active;//高帧率模式的状态,布尔变量

应用定时器2_linux 应用定时器_应用定时器程序-1PLC

inthang_detected;//最新的被发觉的挂起的高精度定时器中断

unsignedlongnr_events;//高精度定时器中断总量

unsignedlongnr_retries;//高精度定时器中断重试总量

unsignedlongnr_hangs;//高精度定时器中断挂起总量

ktime_tmax_hang_time;//在高精度定时器中断触发最长时间

#endif

structhrtimer_clock_baseclock_base[HRTIMER_MAX_CLOCK_BASES];//此CPU时基表针

};

里面的三个结构体应当是最基础的,定义了高精度定时器相关的功能和元素,而且每一个CPU都全套一个定义的结构体,之后初始化hrtimers。

基本的结构体讲完了,下边开始讲API插口。

首先是配置并初始化hrtimers的API。在开始的时侯我们讲structhrtimer的时侯,提及要使用structhrtimer要先初始化,函数申明代码如下:

voidhrtimer_init(structhrtimer*timer,clockid_tclock_id,

enumhrtimer_modemode)//给定时钟初始化定时器

debug_init(timer,clock_id,mode);

__hrtimer_init(timer,clock_id,mode);

以上函数实现了一个高精度定时器的初始化,下边是相关元素的解释:

/**

*hrtimer_init–给定时钟初始化定时器

应用定时器2_应用定时器程序-1PLC_linux 应用定时器

*@timer:即将被初始化的定时器

*@clock_id:即将被用到的时钟

*@mode:定时器模式abs/rel

*/

mode可以使用五个常数,如下:

enumhrtimer_mode{

HRTIMER_MODE_ABS=0x0,/*时间是绝对的*/

HRTIMER_MODE_REL=0x1,/*时间是相对的*/

HRTIMER_MODE_PINNED=0x02,/*定时器被绑定到CPU*/

HRTIMER_MODE_ABS_PINNED=0x02,

HRTIMER_MODE_REL_PINNED=0x03,

};

hrtimer_init()函数上面调用了__hrtimer_init()函数,下边是该函数的原型:

staticvoid__hrtimer_init(structhrtimer*timer,clockid_tclock_id,enumhrtimer_modemode)

structhrtimer_cpu_base*cpu_base;

intbase;

memsettimer,0,sizeof(structhrtimer));

cpu_base=&__raw_get_cpu_var(hrtimer_bases);

应用定时器程序-1PLC_应用定时器2_linux 应用定时器

if(clock_id==CLOCK_REALTIME&&mode!=HRTIMER_MODE_ABS)

clock_id=CLOCK_MONOTONIC;

base=hrtimer_clockid_to_base(clock_id);

timer->base=&cpu_base->clock_base[base];

timerqueue_init(&timer->node);

#ifdefCONFIG_TIMER_STATS

timer->start_site=NULL;

timer->start_pid=-1;

memset(timer->start_comm,0,TASK_COMM_LEN);

#endif

__hrtimer_init()函数调用了structhrtimer_cpu_base结构体对CPU进行相关的初始化,并使用memset()函数,原型如下:

void*memset(void*s,intc,size_tn)

inti;

char*ss=s;

for(i=0;i

ss[i]=c;

returns;

这个函数清空了memory上面的东西,完成了初始化,memset(timer,0,sizeof(structhrtimer))。

在这儿注意一下,还是上面说到的一个问题,我用的源代码是3.2.12的,而2.6.X的源代码里所提供的,虽然只有两个常数

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

233

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

437

2024.03.01

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

764

2023.08.22

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

197

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

190

2025.07.04

javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

175

2023.11.23

java中void的含义
java中void的含义

本专题整合了Java中void的相关内容,阅读专题下面的文章了解更多详细内容。

98

2025.11.27

treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

536

2023.12.01

C++ 高级模板编程与元编程
C++ 高级模板编程与元编程

本专题深入讲解 C++ 中的高级模板编程与元编程技术,涵盖模板特化、SFINAE、模板递归、类型萃取、编译时常量与计算、C++17 的折叠表达式与变长模板参数等。通过多个实际示例,帮助开发者掌握 如何利用 C++ 模板机制编写高效、可扩展的通用代码,并提升代码的灵活性与性能。

10

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.6万人学习

Git 教程
Git 教程

共21课时 | 2.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号