在上一篇文章中,阐述了 Linux 的四种抢占模式,明确了PREEMPT_RT 凭借“内核可抢占”成为目前 Linux 实时化的方案。但“抢占”并不是简单打开一个配置就能实现,它依赖于三个底层机制的彻底重构:实时锁体系、中断线程化、高分辨率定时器。这三者共同消除了标准 Linux 中最主要的延迟来源,让内核具备了工业级确定性。
本文基于 Bootlin 官方文档,从内核执行上下文、锁行为改造、中断处理流程、定时器精度四个维度,阐述PREEMPT_RT 的三个底层机制。
一、内核执行上下文:理解实时锁的基础
在深入锁机制之前,先理清楚目前常见的 Linux 内核中代码运行的四种上下文,这是判断“能否睡眠、能否抢占、能否加锁”的根本依据:
- NMI 上下文
- 硬中断上下文(hardirq)
- 软中断上下文(softirq)
- 任务上下文(task)
PREEMPT_RT围绕一个目标:尽可能让代码运行在可抢占、可调度的任务上下文,缩小原子不可抢占的临界区。
标准 Linux 中,大量代码运行在不可抢占的原子上下文,直接导致Unbounded Latency,而 PREEMPT_RT 把绝大多数原子操作转为可调度、可设置优先级的任务上下文。
二、PREEMPT_RT 锁机制重构:从自旋锁到实时睡眠锁
锁是多任务并发的基础,但标准 Linux 的锁机制是破坏实时性的最主要原因。自旋锁、关闭中断、关闭抢占这些行为都会直接阻塞高优先级任务,因此PREEMPT_RT 对整个内核锁体系做了针对性的修改。
1. 标准 Linux 锁的缺陷
- spinlock_t:加锁时关闭抢占 + 关闭中断,忙等待,临界区不可被抢占;
- rwlock_t:读写自旋锁,同样关闭抢占,读多场景会造成长时间阻塞;
2. PREEMPT_RT 锁的核心改造规则
1)普通 spinlock_t / rwlock_t → 变为睡眠锁(rt_mutex)
加锁不再关闭抢占,等待锁时进程睡眠,而不是忙等待,锁可以被优先级继承,解决优先级反转。
2)仅保留 raw_spinlock_t 作为真正的自旋锁
用于真正不能被打断的硬件底层操作,内核严格限制使用范围,临界区做到最小化。
3)中断上下文锁安全
睡眠锁不能用于硬中断,因此 PREEMPT_RT 把中断转为线程上下文,如下图所示。
3. 睡眠锁 vs 自旋锁:PREEMPT_RT 下的行为
这种改造让内核几乎不再有长时不可抢占区间,是实现全抢占的关键。
三、优先级反转与优先级继承(Priority Inheritance,PI):实时锁的核心
PREEMPT_RT 最核心的可靠性保障,就是优先级继承机制(Priority Inheritance),它专门解决实时系统最危险的优先级反转问题。
1. 什么是优先级反转,以下为具体示例:
- 低优先级任务 C
- 高优先级任务 A
- 中优先级任务 B
- 任务 A 被无限阻塞
这就是优先级反转,会直接导致实时任务超时、系统崩溃。
2. 优先级继承(PI)解决策略
- 当高优先级任务 A 等待低优先级任务 C 持有的锁时;
- 内核自动将 C 的优先级提升到 A 的优先级;
四、中断线程化:PREEMPT_RT 消除中断延迟的方案
标准 Linux 中,硬件中断是破坏实时性的一个关键原因:中断处理时关闭全部中断,执行时间不可控,会直接抢占实时任务。PREEMPT_RT 的解决方案是:将中断线程化(Threaded IRQ)。
1. 标准硬中断的问题
- 中断触发后直接运行硬中断上下文,执行期间关闭中断;
2. PREEMPT_RT 中断线程化原理
PREEMPT_RT 对几乎所有中断做出了如下修改:
- 保留极小的硬中断处理例程,只做硬件应答(ack),因此执行时间固定、极短、可预测;
- 真正的中断处理逻辑被放到内核线程 ,每个中断对应一个内核线程,线程有 PID、可设置优先级、可被调度、可被抢占;
3. 线程化中断的优势
中断处理不再关闭全部中断,中断可被优先级控制,临界区完全可控,因此最终达成延迟不再受驱动代码复杂度影响的目的。
4. 例外场景(不线程化的中断)
但是还是存在极少数中断必须保留硬中断模式,这些例外的执行区间都被严格限制,不会造成不可控延迟,比如有:中断路由相关驱动(irqchip/gpio-irq);cpuidle / cpufreq 驱动(与调度强依赖);标记 为IRQF_NOTHREAD / IRQF_PERCPU 的中断;
五、高分辨率定时器(hrtimer):微秒级定时的基础
实时系统必须依赖高精度时钟,标准 Linux 的定时器基于系统 Tick,精度一般为 1ms~10ms左右,完全无法满足实时要求,PREEMPT_RT 依赖高分辨率定时器(hrtimer) 实现微秒级调度。
1. 标准定时器的缺陷
依赖系统节拍 CONFIG_HZ(100Hz~1000Hz),换算下来最小精度一般为 1ms~10ms,因此无法满足运动控制、数据采集等微秒级需求。
2. hrtimer 核心机制
3. PREEMPT_RT 与 hrtimer 的关系
高分辨率定时器让 Linux 从“毫秒级系统”升级为“微秒级实时系统”。
六、printk 实时化
在 PREEMPT_RT 主线化过程中,printk 是最后一个被解决的阻塞点。
标准 printk 具备下述特性:
PREEMPT_RT 通过对printk做出如下修改:
printk 实时化完成后,PREEMPT_RT 才真正具备全内核的实时功能,增强了调试能力。
七、总结
- PREEMPT_RT 的实时能力来自三大支柱:实时锁、中断线程化、高分辨率定时器。
- 标准 Linux 自旋锁会关闭抢占,PREEMPT_RT 将 spinlock_t 改为睡眠锁,只保留 raw_spinlock_t。
- 优先级继承(PI)
- 中断线程化把硬中断转为可调度、可设优先级的内核线程,消除中断带来的无界延迟。
- 高分辨率定时器 hrtimer
- printk 实时化消除了最后一个内核日志阻塞点,让 PREEMPT_RT 完全主线化。增强调试能力。