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 的原始补丁包含三个关键机制:

  1. 中断线程化(IRQ Threads):将硬中断处理程序改为内核线程,允许被高优先级任务抢占。
  2. 可抢占内核锁(RT Mutex):将自旋锁替换为支持优先级继承的 rt_mutex,避免优先级反转。
  3. 高精度定时器(HRT):引入 hrtimer 框架,提供纳秒级定时精度。
历史意义: Ingo 的补丁首次证明:仅通过修改内核同步与中断机制,就能将 Linux 的调度延迟从数十毫秒降至 100 微秒以下,且无需修改驱动 API。
PREEMPT_RT 补丁核心机制架构(2.6.x 早期) 传统 Linux 内核 中断直接执行 自旋锁禁止抢占 定时器基于 tick 调度延迟 10-100ms Ingo Molnar 2004 年 PREEMPT_RT 内核 中断线程化 RT Mutex + PI hrtimer 高精度 调度延迟 < 100μs 中断线程化 request_threaded_irq() 顶半部 + 底半部线程 RT Mutex 优先级继承协议 替代 spinlock_t 高精度定时器 hrtimer 红黑树 纳秒级触发精度

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
PREEMPT_RT 早期版本演进时间线(2.6.x) 2.6.9 V0.1 原型 2.6.12 V0.5 PI 2.6.18 V1.0 稳定 2.6.24 hrtimer 2.6.31 RCU 抢占 2.6.33 主线化 延迟 > 10ms 延迟 < 50μs

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 驱动。