[toc]
kernel/time/hrtimer.c 高精度定时器(High-Resolution Timers) 纳秒级精度的事件调度 历史与背景 这项技术是为了解决什么特定问题而诞生的? kernel/time/hrtimer.c
实现了**高精度定时器(High-Resolution Timers)框架,它的诞生是为了解决内核中日益增长的、对 亚毫秒级(sub-millisecond)甚至纳秒级(nanosecond)**定时精度的需求。
传统的jiffies
定时器(timer_list
)虽然开销极低,但其精度受限于系统的心跳频率HZ
(通常在4ms到10ms之间)。这对于许多现代应用来说是完全不够的:
用户空间API支持 :POSIX标准定义了nanosleep()
、clock_nanosleep()
和高精度POSIX定时器,这些API要求内核能够提供远超jiffies
精度的定时能力。
多媒体与音频 :专业的音频应用为了实现低延迟处理,需要在非常精确的时间点(例如每1-2毫秒)被唤醒来填充声卡缓冲区。
网络与金融 :高频交易和某些低延迟网络协议需要对超时进行微秒级的精确控制。
内核内部需求 :随着无滴答内核(Tickless Kernel, NO_HZ
)的出现,内核需要一种方法来精确地编程 下一次 需要唤醒CPU的事件,而不是依赖于一个固定的周期性“滴答”。
hrtimer
框架就是为了提供一个统一的、高精度的、可满足所有这些需求的定时器基础设施而设计的。
它的发展经历了哪些重要的里程碑或版本迭代? hrtimer
的引入是Linux内核时间子系统的一次革命性升级。
诞生 (Kernel 2.6.16) :由Thomas Gleixner和Ingo Molnar主导开发,hrtimer
框架被正式合并。它从根本上改变了Linux处理高精度时间的方式。
成为用户空间API的后端 :hrtimer
迅速成为nanosleep()
、setitimer()
(在ITIMER_REAL
模式下)、以及POSIX定时器等高精度API的内核后端实现。
驱动调度器时钟(Scheduler Tick) :在支持NO_HZ
的内核中,周期性的调度器时钟中断不再由一个固定的硬件定时器触发,而是由一个**周期性的高精度定时器(hrtimer
)**来模拟。这使得时钟可以被灵活地停止和启动。
与ktime
的统一 :hrtimer
完全基于ktime_t
(一个表示纳秒的64位数据类型)进行工作,这使得它与内核中其他高精度时间测量(如sched_clock
)保持了一致,并从根本上避免了jiffies
的32位回绕问题。
目前该技术的社区活跃度和主流应用情况如何? hrtimer
是现代Linux内核中一个绝对核心、不可或缺 的组件。
主流应用 :
所有需要精确睡眠的用户空间程序(sleep
一微秒)。
所有实时应用和低延迟多媒体应用。
内核自身的调度和CPU空闲管理。
需要精确、短时间超时的设备驱动程序。
核心原理与设计 它的核心工作原理是什么? hrtimer
的实现远比jiffies
的定时器轮复杂,它结合了高效的数据结构和对底层硬件的精确控制。
时间表示 :所有时间都使用ktime_t
来表示,单位是纳秒。
核心数据结构:红黑树(Red-Black Tree) :
每个CPU核心都有一个自己的hrtimer_cpu_base
结构,其中最重要的就是一个以ktime_t
类型的到期时间为键值排序的红黑树 。
所有在该CPU上排队的hrtimer
都存在于这棵树中。
使用红黑树的优势在于:查找下一个即将到期的定时器 的操作极其高效——它永远是树的最左边的节点 ,获取它的时间复杂度是O(1) 。插入和删除一个定时器的操作是O(log N) 。
与硬件的交互(Clock Event Devices) :
hrtimer
框架依赖于一个硬件抽象层,称为时钟事件设备(Clock Event Devices) 。这是一个能够被编程,在未来的一个精确时间点 触发一次性中断的硬件定时器。
当一个hrtimer
被启动(hrtimer_start()
)时,框架会将其插入到对应CPU的红黑树中。
然后,它会检查这棵树的最左边节点(即最早到期的定时器)。
它将这个最早的到期时间,通过时钟事件设备驱动,编程到硬件定时器 中,让硬件在那个精确的纳秒时刻触发一个中断。
中断处理 :
当硬件定时器中断发生时,hrtimer
的中断处理函数会被调用。
该函数会检查红黑树,将所有已经到期的定时器(可能有多个,如果它们的到期时间非常接近)从树中移除。
对于每个到期的定时器,它会执行其预先注册好的回调函数 。
在处理完所有到期的定时器后,它会再次查看红黑树中新的“最早到期”的定时器,并用它的到期时间重新编程硬件 。
它的主要优势体现在哪些方面?
高分辨率和高精度 :能够提供纳秒级的定时精度,其最终精度受限于底层硬件的能力。
不受jiffies
回绕影响 :使用64位的ktime_t
,不存在回绕问题。
支持多种时钟基准 :可以基于CLOCK_MONOTONIC
(单调时钟)或CLOCK_REALTIME
(真实世界时钟)来设置定时器。
是现代内核特性的基础 :是实现NO_HZ
等高级电源管理和调度功能的基石。
它存在哪些已知的劣势、局限性或在特定场景下的不适用性?
更高的开销 :这是与jiffies
定时器相比最主要的缺点。管理红黑树、频繁地重新编程硬件定时器,都比jiffies
定时器轮简单的链表操作和固定的周期性中断要昂贵得多。
中断风暴 :如果大量定时器被设置在非常接近的时间点到期,可能会导致中断和回调函数集中执行,对系统延迟产生影响。
硬件依赖 :其性能和精度完全取决于底层硬件(时钟事件设备)的能力。
使用场景 在哪些具体的业务或技术场景下,它是首选解决方案? hrtimer
是所有需要亚毫秒级精度定时 的场景的首选解决方案。
实现nanosleep()
:当用户程序需要睡眠几微秒时,内核会设置一个hrtimer
来在精确的时间点后唤醒它。
高频轮询 :一个需要每500微秒检查一次硬件状态的驱动程序,会使用一个周期性的hrtimer
。
调度器时钟 :tick_sched_timer
就是一个周期性的hrtimer
,用于触发进程调度。
精确超时 :一个延迟敏感的网络协议栈,在等待ACK时可能会设置一个几百微秒的hrtimer
超时。
是否有不推荐使用该技术的场景?为什么?
低精度、长周期的定时 :如果你的超时需求是以几十毫-秒甚至秒为单位的(例如,一个200毫秒的超时),使用hrtimer
就是一种不必要的性能浪费 。在这种场景下,应该使用开销更低的**jiffies
定时器(timer_list
)**。
对比分析 请将其 与 其他相似技术 进行详细对比。
特性
高精度定时器 (hrtimer
)
jiffies
/ timer_list
(传统定时器)
sched_clock()
核心用途
高精度 的未来事件调度 (定时器)。
低精度 的未来事件调度 (定时器)。
极低开销 的当前时间戳 获取。
分辨率
高 (纳秒级)。
低 (毫秒级, 由HZ
决定)。
高 (纳秒级)。
功能
安排一个回调函数在未来 被执行。
安排一个回调函数在未来 被执行。
读取 当前时间。不能 安排未来事件。
数据结构
红黑树 。
定时器轮 (哈希链表)。
N/A (直接读取硬件计数器)。
开销
较高 (树操作 + 硬件重编程)。
较低 (链表操作 + 周期性中断)。
极低 。
适用场景
nanosleep
, 实时应用, NO_HZ
。
绝大多数非精度敏感的内核超时。
调度器、ftrace等需要频繁获取时间戳的性能敏感路径。
include/linux/hrtimer_defs.h hrtimer_base_type 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 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 hrtimers_prepare_cpu 与启动时初始化相关的功能 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int hrtimers_prepare_cpu (unsigned int cpu) { struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu); int i; for (i = 0 ; i < HRTIMER_MAX_CLOCK_BASES; i++) { struct hrtimer_clock_base *clock_b = &cpu_base->clock_base[i]; clock_b->cpu_base = cpu_base; seqcount_raw_spinlock_init(&clock_b->seq, &cpu_base->lock); timerqueue_init_head(&clock_b->active); } cpu_base->cpu = cpu; hrtimer_cpu_base_init_expiry_lock(cpu_base); return 0 ; }
hrtimers_cpu_starting 清除 CPU 关闭作中任何剩余状态 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int hrtimers_cpu_starting (unsigned int cpu) { struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); cpu_base->active_bases = 0 ; cpu_base->hres_active = 0 ; cpu_base->hang_detected = 0 ; cpu_base->next_timer = NULL ; cpu_base->softirq_next_timer = NULL ; cpu_base->expires_next = KTIME_MAX; cpu_base->softirq_expires_next = KTIME_MAX; cpu_base->online = 1 ; return 0 ; }
hrtimer_init 初始化高分辨率定时器 1 2 3 4 5 6 void __init hrtimers_init (void ) { hrtimers_prepare_cpu(smp_processor_id()); hrtimers_cpu_starting(smp_processor_id()); open_softirq(HRTIMER_SOFTIRQ, hrtimer_run_softirq); }
hrtimer_update_base 更新一个hrtimer_cpu_base中的所有时钟基座 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 static inline ktime_t hrtimer_update_base (struct hrtimer_cpu_base *base) { ktime_t *offs_real = &base->clock_base[HRTIMER_BASE_REALTIME].offset; ktime_t *offs_boot = &base->clock_base[HRTIMER_BASE_BOOTTIME].offset; ktime_t *offs_tai = &base->clock_base[HRTIMER_BASE_TAI].offset; ktime_t now; now = ktime_get_update_offsets_now(&base->clock_was_set_seq, offs_real, offs_boot, offs_tai); base->clock_base[HRTIMER_BASE_REALTIME_SOFT].offset = *offs_real; base->clock_base[HRTIMER_BASE_BOOTTIME_SOFT].offset = *offs_boot; base->clock_base[HRTIMER_BASE_TAI_SOFT].offset = *offs_tai; return now; }
for_each_active_base 遍历所有活动时钟基座 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 static struct hrtimer_clock_base *__next_base (struct hrtimer_cpu_base *cpu_base , unsigned int *active ) { unsigned int idx; if (!*active) return NULL ; idx = __ffs(*active); *active &= ~(1U << idx); return &cpu_base->clock_base[idx]; } #define for_each_active_base(base, cpu_base, active) \ while ((base = __next_base((cpu_base), &(active))))
__run_hrtimer 执行一个定时器
它的核心作用是:以一种高度并发安全的方式,从定时器队列中移除一个指定的定时器,执行其回调函数,并根据回调的返回值决定是否需要将其重新排队。 它的工作原理是一个被**序列计数器屏障(seqcount_barrier)清晰地划分为三个阶段的、精密的“解锁-调用-重锁”**模型。这个模型是hrtimer能够实现高性能和高并发安全的关键。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, struct hrtimer_clock_base *base, struct hrtimer *timer, ktime_t *now, unsigned long flags) __must_hold(&cpu_base->lock) { enum hrtimer_restart (*fn) (struct hrtimer *) ; bool expires_in_hardirq; int restart; lockdep_assert_held(&cpu_base->lock); debug_deactivate(timer); base->running = timer; raw_write_seqcount_barrier(&base->seq); __remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE, 0 ); fn = ACCESS_PRIVATE(timer, function); if (IS_ENABLED(CONFIG_TIME_LOW_RES)) timer->is_rel = false ; raw_spin_unlock_irqrestore(&cpu_base->lock, flags); trace_hrtimer_expire_entry(timer, now); expires_in_hardirq = lockdep_hrtimer_enter(timer); restart = fn(timer); lockdep_hrtimer_exit(expires_in_hardirq); trace_hrtimer_expire_exit(timer); raw_spin_lock_irq(&cpu_base->lock); if (restart != HRTIMER_NORESTART && !(timer->state & HRTIMER_STATE_ENQUEUED)) enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS); raw_write_seqcount_barrier(&base->seq); WARN_ON_ONCE(base->running != timer); base->running = NULL ; }
__hrtimer_run_queues 执行所有活动的定时器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 static inline s64 hrtimer_get_softexpires_tv64 (const struct hrtimer *timer) { return timer->_softexpires; } static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now, unsigned long flags, unsigned int active_mask) { struct hrtimer_clock_base *base ; unsigned int active = cpu_base->active_bases & active_mask; for_each_active_base(base, cpu_base, active) { struct timerqueue_node *node ; ktime_t basenow; basenow = ktime_add(now, base->offset); while ((node = timerqueue_getnext(&base->active))) { struct hrtimer *timer ; timer = container_of(node, struct hrtimer, node); if (basenow < hrtimer_get_softexpires_tv64(timer)) break ; __run_hrtimer(cpu_base, base, timer, &basenow, flags); if (active_mask == HRTIMER_ACTIVE_SOFT) } } }
hrtimer_run_softirq 运行HRTIMER_SOFTIRQ软中断 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 static __latent_entropy void hrtimer_run_softirq (void ) { struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); unsigned long flags; ktime_t now; hrtimer_cpu_base_lock_expiry(cpu_base); raw_spin_lock_irqsave(&cpu_base->lock, flags); now = hrtimer_update_base(cpu_base); __hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_SOFT); cpu_base->softirq_activated = 0 ; hrtimer_update_softirq_timer(cpu_base, true ); raw_spin_unlock_irqrestore(&cpu_base->lock, flags); hrtimer_cpu_base_unlock_expiry(cpu_base); }
hrtimer_clockid_to_base 将 clockid 转换为 hrtimer_base_type 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 static inline int hrtimer_clockid_to_base (clockid_t clock_id) { switch (clock_id) { case CLOCK_REALTIME: return HRTIMER_BASE_REALTIME; case CLOCK_MONOTONIC: return HRTIMER_BASE_MONOTONIC; case CLOCK_BOOTTIME: return HRTIMER_BASE_BOOTTIME; case CLOCK_TAI: return HRTIMER_BASE_TAI; default : WARN(1 , "Invalid clockid %d. Using MONOTONIC\n" , clock_id); return HRTIMER_BASE_MONOTONIC; } }
hrtimer_setup 初始化高分辨率定时器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 static inline enum hrtimer_restart hrtimer_dummy_timeout (struct hrtimer *unused) { return HRTIMER_NORESTART; } static void __hrtimer_setup(struct hrtimer *timer, enum hrtimer_restart (*function)(struct hrtimer *), clockid_t clock_id, enum hrtimer_mode mode) { bool softtimer = !!(mode & HRTIMER_MODE_SOFT); struct hrtimer_cpu_base *cpu_base ; int base; if (IS_ENABLED(CONFIG_PREEMPT_RT) && !(mode & HRTIMER_MODE_HARD)) softtimer = true ; memset (timer, 0 , sizeof (struct hrtimer)); cpu_base = raw_cpu_ptr(&hrtimer_bases); if (clock_id == CLOCK_REALTIME && mode & HRTIMER_MODE_REL) clock_id = CLOCK_MONOTONIC; base = softtimer ? HRTIMER_MAX_CLOCK_BASES / 2 : 0 ; base += hrtimer_clockid_to_base(clock_id); timer->is_soft = softtimer; timer->is_hard = !!(mode & HRTIMER_MODE_HARD); timer->base = &cpu_base->clock_base[base]; timerqueue_init(&timer->node); if (WARN_ON_ONCE(!function)) ACCESS_PRIVATE(timer, function) = hrtimer_dummy_timeout; else ACCESS_PRIVATE(timer, function) = function; } void hrtimer_setup (struct hrtimer *timer, enum hrtimer_restart (*function)(struct hrtimer *), clockid_t clock_id, enum hrtimer_mode mode) { debug_setup(timer, clock_id, mode); __hrtimer_setup(timer, function, clock_id, mode); } EXPORT_SYMBOL_GPL(hrtimer_setup);
lock_hrtimer_base unlock_hrtimer_base 定时器底座锁 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 static inline struct hrtimer_clock_base *lock_hrtimer_base (const struct hrtimer *timer, unsigned long *flags) __acquires (&timer->base->cpu_base->lock) { struct hrtimer_clock_base *base = timer->base; raw_spin_lock_irqsave(&base->cpu_base->lock, *flags); return base; } static inline void unlock_hrtimer_base (const struct hrtimer *timer, unsigned long *flags) __releases (&timer->base->cpu_base->lock) { raw_spin_unlock_irqrestore(&timer->base->cpu_base->lock, *flags); }
hrtimer_bases 计时器底座 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 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, }, }, .csd = CSD_INIT(retrigger_next_event, NULL ) };
__remove_hrtimer - 删除计时器的内部功能 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 static void __remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, u8 newstate, int reprogram) { struct hrtimer_cpu_base *cpu_base = base->cpu_base; u8 state = timer->state; WRITE_ONCE(timer->state, newstate); if (!(state & HRTIMER_STATE_ENQUEUED)) return ; if (!timerqueue_del(&base->active, &timer->node)) cpu_base->active_bases &= ~(1 << base->index); if (reprogram && timer == cpu_base->next_timer) hrtimer_force_reprogram(cpu_base, 1 ); }
remove_hrtimer 删除 hrtimer 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 static inline int remove_hrtimer (struct hrtimer *timer, struct hrtimer_clock_base *base, bool restart, bool keep_local) { u8 state = timer->state; if (state & HRTIMER_STATE_ENQUEUED) { bool reprogram; debug_deactivate(timer); reprogram = base->cpu_base == this_cpu_ptr(&hrtimer_bases); if (!restart) state = HRTIMER_STATE_INACTIVE; else reprogram &= !keep_local; __remove_hrtimer(timer, base, state, reprogram); return 1 ; } return 0 ; }
enqueue_hrtimer 用于(重新)启动计时器的内部函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 static bool enqueue_hrtimer (struct hrtimer *timer, struct hrtimer_clock_base *base, enum hrtimer_mode mode) { debug_activate(timer, mode); WARN_ON_ONCE(!base->cpu_base->online); base->cpu_base->active_bases |= 1 << base->index; WRITE_ONCE(timer->state, HRTIMER_STATE_ENQUEUED); return timerqueue_add(&base->active, &timer->node); }
__hrtimer_reprogram 重新编程硬件时钟事件设备 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 static void __hrtimer_reprogram(struct hrtimer_cpu_base *cpu_base, struct hrtimer *next_timer, ktime_t expires_next) { cpu_base->expires_next = expires_next; if (!hrtimer_hres_active(cpu_base) || cpu_base->hang_detected) return ; tick_program_event(expires_next, 1 ); }
hrtimer_reprogram 在高分辨率定时器(hrtimer)队列中重新编程时钟事件设备 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 static void hrtimer_reprogram (struct hrtimer *timer, bool reprogram) { struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); struct hrtimer_clock_base *base = timer->base; ktime_t expires = ktime_sub(hrtimer_get_expires(timer), base->offset); WARN_ON_ONCE(hrtimer_get_expires_tv64(timer) < 0 ); if (expires < 0 ) expires = 0 ; if (timer->is_soft) { struct hrtimer_cpu_base *timer_cpu_base = base->cpu_base; if (timer_cpu_base->softirq_activated) return ; if (!ktime_before(expires, timer_cpu_base->softirq_expires_next)) return ; timer_cpu_base->softirq_next_timer = timer; timer_cpu_base->softirq_expires_next = expires; if (!ktime_before(expires, timer_cpu_base->expires_next) || !reprogram) return ; } if (base->cpu_base != cpu_base) return ; if (expires >= cpu_base->expires_next) return ; if (cpu_base->in_hrtirq) return ; cpu_base->next_timer = timer; __hrtimer_reprogram(cpu_base, timer, expires); }
hrtimer_start_range_ns - 启动高分辨率定时器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, u64 delta_ns, const enum hrtimer_mode mode, struct hrtimer_clock_base *base) { struct hrtimer_cpu_base *this_cpu_base = this_cpu_ptr(&hrtimer_bases); struct hrtimer_clock_base *new_base ; bool force_local, first; force_local = base->cpu_base == this_cpu_base; force_local &= base->cpu_base->next_timer == timer; force_local &= this_cpu_base->online; remove_hrtimer(timer, base, true , force_local); if (mode & HRTIMER_MODE_REL) tim = ktime_add_safe(tim, base->get_time()); tim = hrtimer_update_lowres(timer, tim, mode); hrtimer_set_expires_range_ns(timer, tim, delta_ns); if (!force_local) { new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED); } else { new_base = base; } first = enqueue_hrtimer(timer, new_base, mode); if (!force_local) { if (hrtimer_base_is_online(this_cpu_base)) return first; if (first) { struct hrtimer_cpu_base *new_cpu_base = new_base->cpu_base; smp_call_function_single_async(new_cpu_base->cpu, &new_cpu_base->csd); } return 0 ; } hrtimer_force_reprogram(new_base->cpu_base, 1 ); return 0 ; } void hrtimer_start_range_ns (struct hrtimer *timer, ktime_t tim, u64 delta_ns, const enum hrtimer_mode mode) { struct hrtimer_clock_base *base ; unsigned long flags; if (!IS_ENABLED(CONFIG_PREEMPT_RT)) WARN_ON_ONCE(!(mode & HRTIMER_MODE_SOFT) ^ !timer->is_soft); else WARN_ON_ONCE(!(mode & HRTIMER_MODE_HARD) ^ !timer->is_hard); base = lock_hrtimer_base(timer, &flags); if (__hrtimer_start_range_ns(timer, tim, delta_ns, mode, base)) hrtimer_reprogram(timer, true ); unlock_hrtimer_base(timer, &flags); } EXPORT_SYMBOL_GPL(hrtimer_start_range_ns);
hrtimer_start 重新启动 HRTimter 1 2 3 4 5 6 7 8 9 10 11 12 13 static inline void hrtimer_start (struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode) { hrtimer_start_range_ns(timer, tim, 0 , mode); }
hrtimer_run_queues - 运行高精度定时器队列
它的核心作用是:在每个jiffy到来时,检查并执行所有已经到期的、不可延迟的硬中断高精度定时器(hrtimer),并负责触发HRTIMER_SOFTIRQ软中断来处理可延迟的软中断定时器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 static inline int hrtimer_hres_active (struct hrtimer_cpu_base *cpu_base) { return IS_ENABLED(CONFIG_HIGH_RES_TIMERS) ? cpu_base->hres_active : 0 ; } void hrtimer_run_queues (void ) { struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); unsigned long flags; ktime_t now; if (hrtimer_hres_active(cpu_base)) return ; if (tick_check_oneshot_change(!hrtimer_is_hres_enabled())) { hrtimer_switch_to_hres(); return ; } raw_spin_lock_irqsave(&cpu_base->lock, flags); now = hrtimer_update_base(cpu_base); if (!ktime_before(now, cpu_base->softirq_expires_next)) { cpu_base->softirq_expires_next = KTIME_MAX; cpu_base->softirq_activated = 1 ; raise_timer_softirq(HRTIMER_SOFTIRQ); } __hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_HARD); raw_spin_unlock_irqrestore(&cpu_base->lock, flags); }
hrtimer_active: 无锁高精度定时器状态检查 本代码片段提供了一个高性能、无锁的函数 hrtimer_active
,用于检查一个高精度定时器(hrtimer)是否处于“激活”状态。根据内核定义,一个定时器在以下三种情况下被认为是激活的:1) 已被添加到其时钟基座(clock base)的红黑树中等待触发;2) 其回调函数正在执行中;3) 正在被迁移到另一个 CPU。此函数的关键设计目标是在保证绝对不会出现“假阴性”(即定时器是激活的但函数返回 false
)的前提下,尽可能快地完成检查。
实现原理分析 此函数是内核中无锁编程的经典范例,其核心实现是一种被称为“顺序锁”(Seqlock)的乐观同步技术。它允许多个读取者(hrtimer_active
的调用者)与一个写入者(修改定时器状态的代码)并发执行,读取者通过一个重试循环来确保其读取数据的一致性。
乐观读取与重试循环 : 函数的主体是一个 do-while
循环。它首先“乐观地”读取定时器的状态,不获取任何锁。然后,在循环的末尾,它会验证在读取期间是否有写入者修改了数据。如果检测到冲突,整个读取操作就会被放弃并从头重试。
顺序锁(Seqlock)的使用 :
raw_read_seqcount_begin(&base->seq)
: 在读取任何受保护的数据之前,此宏会读取当前时钟基座 base
的序列计数器 seq
的值。
数据读取 : 随后,代码读取 timer->state
和 base->running
这两个关键状态。
read_seqcount_retry(&base->seq, seq)
: 在读取完成后,此宏会再次检查序列计数器。如果计数器的值与开始时读取的 seq
不一致,或者如果计数器的值是奇数(表示写入者正在进行写操作),则意味着在读取期间数据可能已被修改,处于不一致的状态。此时,read_seqcount_retry
返回 true
,导致循环重试。
处理定时器迁移 : 除了 seqlock,循环的退出条件还有一个 base != READ_ONCE(timer->base)
的检查。这是一个处理定时器跨 CPU 迁移的关键细节。在读取 seq
和检查状态之间,定时器可能被迁移到了一个新的 base
。如果发生这种情况,我们之前基于旧 base
的 seqlock 检查就变得毫无意义。因此,必须确认 timer->base
指针在整个过程中没有改变。如果改变了,也必须重试整个循环,以从新的 base
开始检查。
READ_ONCE
: READ_ONCE
宏的使用确保了编译器不会对指针的读取进行优化(如缓存到寄存器中),而是每次都从内存中真实地加载 timer->base
的值,这对于正确检测并发修改至关重要。
代码分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 bool hrtimer_active (const struct hrtimer *timer) { struct hrtimer_clock_base *base ; unsigned int seq; do { base = READ_ONCE(timer->base); seq = raw_read_seqcount_begin(&base->seq); if (timer->state != HRTIMER_STATE_INACTIVE || base->running == timer) return true ; } while (read_seqcount_retry(&base->seq, seq) || base != READ_ONCE(timer->base)); return false ; } EXPORT_SYMBOL_GPL(hrtimer_active);
高精度定时器的取消与同步 (hrtimer_cancel, hrtimer_try_to_cancel) 本代码片段是 Linux 内核高精度定时器(hrtimer)子系统的核心组成部分,提供了两种用于取消(停止)一个已启动定时器的关键函数。hrtimer_try_to_cancel
是一个非阻塞的尝试取消操作,如果定时器的回调函数正在执行,它会立即失败并返回。hrtimer_cancel
则是一个阻塞的、保证成功(除非定时器未激活)的取消操作,它会在回调函数运行时进行等待,直至回调执行完毕且定时器被成功移除。
实现原理分析 这两个函数的核心是处理一个关键的竞态条件:当一个任务试图取消定时器时,该定时器可能恰好到期,其回调函数正在被或即将被另一个上下文(通常是软中断)执行。
无锁状态检查 (hrtimer_active
) : hrtimer_try_to_cancel
的第一步是调用 hrtimer_active(timer)
。这是一个无锁的优化检查,它通过读取定时器的状态位来判断定时器是否可能处于“激活”(已入队或正在运行回调)状态。如果定时器未激活,函数可以安全地提前返回,避免了获取重量级锁的开销。
基于锁的原子移除 : 如果定时器是激活的,函数必须通过 lock_hrtimer_base
获取保护该定时器所在时钟基座(clock base)的自旋锁。这个锁保护了管理 hrtimer 的红黑树数据结构。在锁的保护下,代码通过 hrtimer_callback_running(timer)
再次精确检查回调函数是否正在运行。如果回调没有运行,remove_hrtimer
函数会被调用,它会将定时器从红黑树中安全地移除,完成取消操作。
阻塞式重试机制 (hrtimer_cancel
) : hrtimer_cancel
的实现体现了“循环-尝试-等待”的设计模式。它在一个 do-while
循环中反复调用 hrtimer_try_to_cancel
。
如果 hrtimer_try_to_cancel
返回 >= 0
,表示取消成功或定时器本就未激活,循环结束。
如果返回 -1
,则说明遇到了回调函数正在运行的竞态。此时,hrtimer_cancel_wait_running(timer)
会被调用。这个函数会进入一个忙等待循环(通常使用 cpu_relax()
),等待定时器的“回调运行中”标志位被清除。重要的是,在等待期间,锁已被释放,中断也是开启的,这使得执行回调的软中断上下文能够正常完成其工作。一旦回调结束,do-while
循环会进行下一次尝试,这次 hrtimer_try_to_cancel
就能够成功了。
代码分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 static inline void hrtimer_cancel_wait_running (struct hrtimer *timer) { cpu_relax(); } int hrtimer_cancel (struct hrtimer *timer) { int ret; do { ret = hrtimer_try_to_cancel(timer); if (ret < 0 ) hrtimer_cancel_wait_running(timer); } while (ret < 0 ); return ret; } EXPORT_SYMBOL_GPL(hrtimer_cancel); static inline int hrtimer_callback_running (struct hrtimer *timer) { return timer->base->running == timer; } int hrtimer_try_to_cancel (struct hrtimer *timer) { struct hrtimer_clock_base *base ; unsigned long flags; int ret = -1 ; if (!hrtimer_active(timer)) return 0 ; base = lock_hrtimer_base(timer, &flags); if (!hrtimer_callback_running(timer)) ret = remove_hrtimer(timer, base, false , false ); unlock_hrtimer_base(timer, &flags); return ret; } EXPORT_SYMBOL_GPL(hrtimer_try_to_cancel);