浅析linux 内核 高精度定时器(hrtimer)实现机制(一)

本文深入探讨Linux内核的高精度定时器(hrtimer)机制,包括hrtimer概述、相关数据结构如hrtimer、hrtimer_clock_base和hrtimer_cpu_base,以及初始化、移除、激活等API。hrtimer提供纳秒级精度,以满足对时间精确度有高要求的场景,并能在低精度和高精度模式间切换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 hrtimer 概述

在Linux内核中已经存在了一个管理定时器的通用框架。不过它也有很多不足,最大的问题是其精度不是很高。哪怕底层的定时事件设备精度再高,定时器层的分辨率只能达到Tick级别,按照内核配置选项的不同,在100Hz到1000Hz之间。但是,原有的定时器层由于实现教早,应用广泛,如果完全替换掉会引入大量代码改动。因此,Linux内核又独立设计出了一个叫高精度定时器层(High Resolution Timer)的框架,可以为我们提供纳秒级的定时精度,以满足对精确时间有迫切需求的应用程序或内核驱动程序。

高分辨率定时器是建立在每CPU私有独占的本地时钟事件设备上的,对于一个多处理器系统,如果只有全局的时钟事件设备,高分辨率定时器是无法工作的。因为如果没有每CPU私有独占的时钟事件设备,当到期中断发生时系统必须产生夸处理器中断来通知其它CPU完成相应的工作,而过多的夸处理器中断会带来很大的系统开销,这样会令使用高分辨率定时器的代价大大增加,还不如不用。为了让内核支持高分辨率定时器,必须要在编译的时候打开编译选项CONFIG_HIGH_RES_TIMERS。

高分辨率定时器层有两种工作模式:低精度模式与高精度模式。虽然高分辨率定时器子系统是为高精度定时器准备的,但是系统可能在运行过程中动态切换到不同精度和模式的定时事件设备,因此高精度定时器层必须能够在低精度模式与高精度模式下自由切换。

高分辨率定时器层使用红黑树来组织各个高分辨率定时器。随着系统的运行,高分辨率定时器不停地被创建和销毁,新的高分辨率定时器按顺序被插入到红黑树中,树的最左边的节点就是最快到期的定时器。

2 相关数据结构

2.1 hrtimer

高分辨率定时器由hrtimer结构体表示(代码位于include/linux/hrtimer.h中):

struct hrtimer {
	struct timerqueue_node		node;
	ktime_t				_softexpires;
	enum hrtimer_restart		(*function)(struct hrtimer *);
	struct hrtimer_clock_base	*base;
	u8				state;
	u8				is_rel;
	u8				is_soft;
	u8				is_hard;
};

node:是一个timerqueue_node结构体变量。这个结构体中有两个成员,node是红黑树的节点,expires:表示该定时器的硬超时时间:

struct timerqueue_node {
    struct rb_node node;
    ktime_t expires;
};

_softexpires:表示该定时器的软超时时间。高精度定时器一般都有一个到期的时间范围,而不像(低精度)定时器那样就是一个时间点。这个时间范围的前时间点就是软超时时间,而后一个时间点就是硬超时时间。达到软超时时间后,还可以再拖一会再调用超时回调函数,而到达硬超时时间后就不能再拖了。

function:定时器到期后的回调函数。

base:指向包含该高分辨率定时器的的hrtimer_clock_base结构体。

state:用来表示该高分辨率定时器当前所处的状态,目前共有两种状态:

/* 表示定时器还未激活 */
#define HRTIMER_STATE_INACTIVE	0x00
/* 表示定时器已激活(入列) */
#define HRTIMER_STATE_ENQUEUED	0x01

is_rel:表示该定时器的到期时间是否是相对时间。is_soft:表示该定时器是否是“软”定时器。
is_hard:表示该定时器是否是“硬”定时器。

2.2 hrtimer_clock_base

struct hrtimer_clock_base {
	struct hrtimer_cpu_base	*cpu_base;
	unsigned int		index;
	clockid_t		clockid;
	seqcount_t		seq;
	struct hrtimer		*running;
	struct timerqueue_head	active;
	ktime_t			(*get_time)(void);
	ktime_t			offset;
} __hrtimer_clock_base_align;

cpu_base:指向所属CPU的hrtimer_cpu_base结构体。
index:表示该结构体在当前CPU的hrtimer_cpu_base结构体中clock_base数组中所处的下标。
clockid:表示当前时钟类型的ID值。
seq:顺序锁,在处理到期定时器的函数__run_hrtimer中会用到。
running:指向当前正在处理的那个定时器。
active:红黑树,包含了所有使用该时间类型的定时器。
get_time:是一个函数指针,指定了如何获取该时间类型的当前时间的函数。由于不同类型的时间在Linux中都是由时间维护层来统一管理的,因此这些函数都是在时间维护层里面定义好的。
offset:表示当前时间类型和单调时间之间的差值。

2.3 hrtimer_cpu_base

每个CPU单独管理属于自己的高分辨率定时器,为了方便管理,专门定义了一个结构体hrtimer_cpu_base:

struct hrtimer_cpu_base {
	raw_spinlock_t			lock;
	unsigned int			cpu;
	unsigned int			active_bases;
	unsigned int			clock_was_set_seq;
	unsigned int			hres_active		: 1,
					in_hrtirq		: 1,
					hang_detected		: 1,
					softirq_activated       : 1;
#ifdef CONFIG_HIGH_RES_TIMERS
	unsigned int			nr_events;
	unsigned short			nr_retries;
	unsigned short			nr_hangs;
	unsigned int			max_hang_time;
#endif
#ifdef CONFIG_PREEMPT_RT
	......
#endif
	ktime_t				expires_next;
	struct hrtimer			*next_timer;
	ktime_t				softirq_expires_next;
	struct hrtimer
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值