Linux hrtimer 数据结构

文章目录

  • [1. 前言](#1. 前言)
  • [2. hrtimer 数据结构](#2. hrtimer 数据结构)

1. 前言

限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。

2. hrtimer 数据结构

Linux hrtimer 核心数据结构主要由 struct hrtimer_cpu_basestruct hrtimer_clock_base 构成(摘自 Linux 4.14.336 内核):

c 复制代码
// include/linux/hrtimer.h

/**
 * struct hrtimer_cpu_base - the per cpu clock bases
 * @lock:		lock protecting the base and associated clock bases
 *			and timers
 * @cpu:		cpu number
 * @active_bases:	Bitfield to mark bases with active timers
 * @clock_was_set_seq:	Sequence counter of clock was set events
 * @hres_active:	State of high resolution mode
 * @in_hrtirq:		hrtimer_interrupt() is currently executing
 * @hang_detected:	The last hrtimer interrupt detected a hang
 * @softirq_activated:	displays, if the softirq is raised - update of softirq
 *			related settings is not required then.
 * @nr_events:		Total number of hrtimer interrupt events
 * @nr_retries:		Total number of hrtimer interrupt retries
 * @nr_hangs:		Total number of hrtimer interrupt hangs
 * @max_hang_time:	Maximum time spent in hrtimer_interrupt
 * @softirq_expiry_lock: Lock which is taken while softirq based hrtimer are
 *			 expired
 * @expires_next:	absolute time of the next event, is required for remote
 *			hrtimer enqueue; it is the total first expiry time (hard
 *			and soft hrtimer are taken into account)
 * @next_timer:		Pointer to the first expiring timer
 * @softirq_expires_next: Time to check, if soft queues needs also to be expired
 * @softirq_next_timer: Pointer to the first expiring softirq based timer
 * @clock_base:		array of clock bases for this cpu
 *
 * Note: next_timer is just an optimization for __remove_hrtimer().
 *	 Do not dereference the pointer because it is not reliable on
 *	 cross cpu removals.
 */
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;
	/*
	 * tick 中断中, 按下一个到期 hrtimer 时间编程 tick 设备重试的
	 * 累加次数, 期间可能出错了. 每个 tick 中断最多重试 3 次.
	 */
	unsigned short			nr_retries;
	/* tick 中断中, 按下一个到期 hrtimer 时间编程 tick 设备出错的 累加次数 */
	unsigned short			nr_hangs;
	unsigned int			max_hang_time;
#endif
	spinlock_t			softirq_expiry_lock;
	/*
	 * hrtimer_cpu_base 的所有(类型(包括 hard,soft) hrtimer_clock_base 
	 * clock_base[]) 的 hrtimer 红黑树队列中, 下一个到期时间最早的 hrtimer 
	 * 的 超时时间点.
	 */
	ktime_t				expires_next;
	struct hrtimer			*next_timer; /* 下一个到期的 hrtimer */
	ktime_t				softirq_expires_next; /* 下一个最早到期的 soft hrtimer 时间点 */
	struct hrtimer			*softirq_next_timer; /* 下一个最早到期的 soft hrtimer */
	struct hrtimer_clock_base	clock_base[HRTIMER_MAX_CLOCK_BASES];
} ____cacheline_aligned;

/**
 * struct hrtimer_clock_base - the timer base for a specific clock
 * @cpu_base:		per cpu clock base
 * @index:		clock type index for per_cpu support when moving a
 *			timer to a base on another cpu.
 * @clockid:		clock id for per_cpu support
 * @seq:		seqcount around __run_hrtimer
 * @running:		pointer to the currently running hrtimer
 * @active:		red black tree root node for the active timers
 * @get_time:		function to retrieve the current time of the clock
 * @offset:		offset of this clock to the monotonic base
 */
struct hrtimer_clock_base {
	/*
	 * 一个 hrtimer 关联的 一个 每 cpu 的 tick 设备, 这是 一对一 的关系, 
	 * 基于该 cpu 的 tick 设备的 cycle 来作为时间基准, 这在系统初始化时
	 * 就已经设定好了, 后续不会变更:
	 * 1) boot CPU
	 *    start_kernel()
	 *      hrtimers_init()
	 *        hrtimers_prepare_cpu(smp_processor_id());
	 *          struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu);
	 *           int i;
	 *
	 *           // 为当前 CPU @cpu 所有类型的 hrtimer_clock_base 设定 hrtimer_cpu_base
	 *           for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
	 *             cpu_base->clock_base[i].cpu_base = cpu_base;
	 *             timerqueue_init_head(&cpu_base->clock_base[i].active);
	 *           }
	 * 2) 非 BOOT CPU
	 *    CPU 热插拔状态 CPUHP_HRTIMERS_PREPARE 触发 hrtimers_prepare_cpu()
	 */
	struct hrtimer_cpu_base	*cpu_base;
	unsigned int		index;
	clockid_t		clockid;
	seqcount_t		seq;
	struct hrtimer		*running; /* 当前正在运行的 hrtimer (回调), NULL 表示没有正在运行的 hrtimer */
	struct timerqueue_head	active; /* 激活 hrtimer 的红黑树(根) */
	ktime_t			(*get_time)(void);
	ktime_t			offset; /* 每个 hrtimer_clock_base 都维护自身独立的时间线 */
} __hrtimer_clock_base_align;

struct hrtimer_cpu_base 是 per-cpu 的数据结构,为其包含的各种类型的 struct hrtimer_clock_base 定义时钟基准:

c 复制代码
// include/linux/hrtimer.h
enum  hrtimer_base_type {
	HRTIMER_BASE_MONOTONIC,
	HRTIMER_BASE_REALTIME,
	HRTIMER_BASE_BOOTTIME,
	HRTIMER_BASE_TAI,
	HRTIMER_BASE_MONOTONIC_SOFT,
	HRTIMER_BASE_REALTIME_SOFT,
	HRTIMER_BASE_BOOTTIME_SOFT,
	HRTIMER_BASE_TAI_SOFT,
	HRTIMER_MAX_CLOCK_BASES,
};

// kernel/time/hrtimer.c
/*
 * The timer bases:
 *
 * There are more clockids than hrtimer bases. Thus, we index
 * into the timer bases by the hrtimer_base_type enum. When trying
 * to reach a base using a clockid, hrtimer_clockid_to_base()
 * is used to convert from clockid to the proper hrtimer_base_type.
 */
DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
{
	.lock = __RAW_SPIN_LOCK_UNLOCKED(hrtimer_bases.lock),
	.clock_base =
	{
		{
			.index = HRTIMER_BASE_MONOTONIC,
			.clockid = CLOCK_MONOTONIC,
			.get_time = &ktime_get,
		},
		{
			.index = HRTIMER_BASE_REALTIME,
			.clockid = CLOCK_REALTIME,
			.get_time = &ktime_get_real,
		},
		{
			.index = HRTIMER_BASE_BOOTTIME,
			.clockid = CLOCK_BOOTTIME,
			.get_time = &ktime_get_boottime,
		},
		{
			.index = HRTIMER_BASE_TAI,
			.clockid = CLOCK_TAI,
			.get_time = &ktime_get_clocktai,
		},
		{
			.index = HRTIMER_BASE_MONOTONIC_SOFT,
			.clockid = CLOCK_MONOTONIC,
			.get_time = &ktime_get,
		},
		{
			.index = HRTIMER_BASE_REALTIME_SOFT,
			.clockid = CLOCK_REALTIME,
			.get_time = &ktime_get_real,
		},
		{
			.index = HRTIMER_BASE_BOOTTIME_SOFT,
			.clockid = CLOCK_BOOTTIME,
			.get_time = &ktime_get_boottime,
		},
		{
			.index = HRTIMER_BASE_TAI_SOFT,
			.clockid = CLOCK_TAI,
			.get_time = &ktime_get_clocktai,
		},
	}
};

最终形成的数据结构如下图:

相关推荐
河码匠2 小时前
Linux sar 命令
linux·运维·网络
偷懒下载原神2 小时前
【linux操作系统】进程间通信--管道
linux·运维·服务器
异步的告白2 小时前
嵌入式Linux学习-Makefile基本语法:目标、依赖、命令、伪目标.PHONY
linux
!沧海@一粟!2 小时前
VMware升级操作指南与常见问题
linux·运维·服务器
是小小张呀2 小时前
Linux系统查看常用命令
linux
Apibro2 小时前
【Linux 】解压/压缩命令全解析:unzip、tar、gzip、bzip2、xz
linux
IMPYLH2 小时前
Linux 的 base32 命令
linux·运维·服务器·bash·shell
7yewh3 小时前
MCU 卷积神经网络部署 · 深度技术指南
linux·嵌入式硬件·ai·嵌入式
无垠的广袤3 小时前
【ChatECNU 大语言模型】基于 Linux 开发板的 OpenClaw 部署方案
linux·人工智能·语言模型