文章目录
- [1. 前言](#1. 前言)
- [2. hrtimer 数据结构](#2. hrtimer 数据结构)
1. 前言
限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。
2. hrtimer 数据结构
Linux hrtimer 核心数据结构主要由 struct hrtimer_cpu_base 和 struct 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,
},
}
};
最终形成的数据结构如下图:
