3. PREEMPT_RT 补丁起源:Ingo Molnar 与 Thomas Gleixner 的贡献
3.1 实时 Linux 的早期探索与瓶颈
在 2.4.x / 2.6.x 早期内核时代,Linux 被广泛认为“不适合硬实时”。主要原因在于内核态抢占点过少、中断处理不可控、自旋锁持有期间禁止抢占。社区尝试过多种方案:
- RTLinux (FSMLabs):采用双内核方案,在 Linux 之下运行一个微实时内核,Linux 作为最低优先级任务。商业闭源,与主线割裂。
- RTAI:类似双内核,但开源,维护成本高,API 与主线差异大。
- Xenomai:双内核 + 皮肤机制,兼容多种 RTOS API,但同样无法合入主线。
这些方案虽然能提供微秒级确定性,但代价是:无法直接使用标准 Linux 驱动、调试困难、社区分裂。业界迫切需要一种纯内核态、可合入主线、对驱动透明的实时方案。
关键矛盾: 双内核方案牺牲了 Linux 的生态兼容性,而主线内核的调度延迟(通常 10-100 ms)无法满足工业控制、音频处理等场景的 1 ms 以下 deadline 要求。
3.2 Ingo Molnar 的突破:PREEMPT_RT 补丁的诞生
2004 年,Red Hat 的 Ingo Molnar 发布了第一版 PREEMPT_RT 补丁(针对 2.6.9 内核)。其核心思想是:不改变 Linux 整体架构,而是通过细粒度锁替换、中断线程化、优先级继承等手段,将内核不可抢占区域压缩到极致。
Ingo 的原始补丁包含三个关键机制:
- 中断线程化(IRQ Threads):将硬中断处理程序改为内核线程,允许被高优先级任务抢占。
- 可抢占内核锁(RT Mutex):将自旋锁替换为支持优先级继承的 rt_mutex,避免优先级反转。
- 高精度定时器(HRT):引入 hrtimer 框架,提供纳秒级定时精度。
历史意义: Ingo 的补丁首次证明:仅通过修改内核同步与中断机制,就能将 Linux 的调度延迟从数十毫秒降至 100 微秒以下,且无需修改驱动 API。
3.3 Thomas Gleixner 的接棒与系统化重构
2005-2007 年间,Thomas Gleixner(Linutronix 创始人)接管了 PREEMPT_RT 补丁的维护工作。他不仅修复了 Ingo 原型中的大量竞态条件,还进行了系统化的重构:
| 贡献领域 | 具体工作 | 影响 |
|---|---|---|
| 中断子系统重写 | 统一 threaded IRQ 框架,支持强制/可选线程化 | 所有驱动无需修改即可运行在 RT 模式下 |
| 锁机制标准化 | 将 raw_spinlock 与 spinlock 分离,rt_mutex 成为核心原语 | 非 RT 内核零开销,RT 内核自动获得 PI 能力 |
| RCU 抢占支持 | 实现可抢占 RCU(Preemptible RCU) | 读侧临界区可被抢占,减少延迟抖动 |
| 测试与验证 | 引入 cyclictest、rt-tests 套件,建立延迟基准 | 社区有了统一的实时性能度量标准 |
维护挑战: 2.6.x 时代的内核版本迭代极快(每 2-3 个月一个稳定版),Thomas 团队需要为每个版本重新适配 RT 补丁,同时向后兼容数百个驱动。这催生了后来的 linux-rt-devel 邮件列表和自动化 CI 体系。
3.4 早期版本演进(2.6.9 ~ 2.6.33)
从 2.6.9 到 2.6.33,PREEMPT_RT 补丁经历了从“实验性 hack”到“生产级候选”的蜕变。下表列出了关键里程碑版本:
| 内核版本 | 补丁版本 | 发布时间 | 核心改进 |
|---|---|---|---|
| 2.6.9 | V0.1 | 2004-10 | Ingo 首次发布,中断线程化原型 |
| 2.6.12 | V0.5 | 2005-06 | Thomas 加入,引入 rt_mutex 与 PI |
| 2.6.18 | V1.0 | 2006-09 | 第一个稳定 API 版本,支持 x86/ARM |
| 2.6.24 | V2.0 | 2008-01 | hrtimer 合入主线,RT 补丁依赖减少 |
| 2.6.31 | V2.6.31-rt | 2009-09 | Preemptible RCU 合入,延迟降至 50μs 以下 |
| 2.6.33 | V2.6.33-rt | 2010-02 | 主线化进程启动,大量 RT 代码进入 staging |
3.5 补丁结构:如何为 2.6.x 内核打 RT 补丁
在 2.6.x 时代,PREEMPT_RT 以独立补丁集形式发布,需要手动下载并应用到内核源码。典型的操作流程如下:
# 下载对应内核版本的 RT 补丁
wget https://www.kernel.org/pub/linux/kernel/projects/rt/2.6.33/patch-2.6.33-rt24.patch.gz
# 解压内核源码
tar xf linux-2.6.33.tar.bz2
cd linux-2.6.33
# 应用 RT 补丁
zcat ../patch-2.6.33-rt24.patch.gz | patch -p1
# 配置内核,启用 PREEMPT_RT
make menuconfig
# 进入 Kernel Features → Preemption Model
# 选择 "Fully Preemptible Kernel (RT)"
# 编译安装
make -j$(nproc)
make modules_install
make install
注意事项: 2.6.x 时代的 RT 补丁与内核版本严格绑定,不能跨版本使用。补丁文件名中的
rt24 表示该补丁的第 24 次修订,通常每个内核版本会有多个迭代(如 rt1 ~ rt30+)。
3.6 早期 RT 补丁的局限性
尽管 PREEMPT_RT 在 2.6.x 时代取得了巨大进步,但仍存在以下不足:
- 代码侵入性大:补丁修改了内核中数百个文件,主线维护者难以审查。
- 性能开销:RT Mutex 和中断线程化带来了 5-15% 的吞吐量下降,部分场景不可接受。
- 架构支持有限:早期仅支持 x86、ARM、PowerPC,MIPS 和 SPARC 支持不完整。
- 驱动兼容性:部分硬件驱动在中断线程化后出现时序问题,需要厂商提供 RT-aware 驱动。