3、PREEMPT_RT补丁简介:发展历史、主线演进与核心关系
聊实时Linux,绕不开PREEMPT_RT。这个补丁集,说白了就是让Linux内核具备硬实时能力的关键。我最早接触它是在2012年,当时一个工业控制项目要求响应延迟必须控制在100微秒以内,标准内核根本做不到。嗯,那时候我就开始深入研究PREEMPT_RT了。
3.1 PREEMPT_RT的发展历史
PREEMPT_RT的故事,得从2004年说起。当时Ingo Molnar(对,就是那个维护调度器的牛人)发起了这个项目。他的目标很明确:让Linux能跑在硬实时场景下。
我简单梳理一下关键时间节点:
| 时间 | 里程碑 | 我的评价 |
|---|---|---|
| 2004年 | Ingo Molnar发布首个PREEMPT_RT补丁 | 那时候补丁还很小,改动集中在中断线程化 |
| 2005-2007年 | 逐步加入自旋锁可抢占、高精度定时器 | 我记得当时社区争议很大,很多人觉得没必要 |
| 2009年 | Thomas Gleixner接手维护 | 这位老兄把代码质量提升了一个档次 |
| 2015年 | 开始大规模主线合入 | 我参与的一个项目正好赶上这波,爽 |
| 2023年 | PREEMPT_RT接近完全主线化 | 现在基本只剩少量核心补丁还在维护 |
为什么会拖这么久?说白了,实时性改动会触及内核最底层的同步机制。你想想看,把自旋锁改成可抢占的,这相当于把整个内核的并发模型重写了一遍。我在项目中遇到过,光是测试回归就跑了三个月。
3.2 主线内核的实时演进
主线内核这些年,其实一直在吸收PREEMPT_RT的成果。我把它分成三个阶段:
阶段一:PREEMPT_NONE → PREEMPT_VOLUNTARY → PREEMPT
早期内核只有PREEMPT_NONE,也就是完全不抢占。后来加了PREEMPT_VOLUNTARY,在特定点主动让出CPU。再到PREEMPT,允许内核态被抢占。嗯,这三个选项现在还在,但已经不够用了。
阶段二:PREEMPT_RT补丁的逐步合入
从4.x内核开始,大量PREEMPT_RT特性被合入主线:
- 中断线程化:把硬中断变成内核线程,降低中断延迟抖动
- 高精度定时器:hrtimer,精度从jiffy级别提升到纳秒级
- 可抢占自旋锁:spin_lock变成可被抢占的,减少优先级反转
- RCU改进:让RCU在实时场景下更可预测
核心变化:主线内核从"尽力而为"的调度,变成了"确定性优先"的调度。这个转变花了将近20年。
阶段三:PREEMPT_RT成为内核选项
到了5.x内核,你可以在内核配置里直接选PREEMPT_RT_FULL。虽然还不是默认选项,但已经不需要打补丁了。我建议新手直接选这个选项测试,省去很多麻烦。
3.3 PREEMPT_RT与主线内核的关系
这个问题经常有人问。我直接说结论:PREEMPT_RT是主线内核的超集。
具体来说:
- 主线内核提供基础实时能力(PREEMPT、PREEMPT_VOLUNTARY)
- PREEMPT_RT在主线基础上增加硬实时特性
- 大部分PREEMPT_RT代码最终会合入主线
- 但总有一些核心补丁留在主线外(比如完全可抢占的slub分配器)
我的经验:如果你只需要软实时(延迟1ms以内),主线内核的PREEMPT就够用了。但如果你需要硬实时(延迟100us以内),必须上PREEMPT_RT。我曾经在一个机器人项目中试过只用主线PREEMPT,结果电机控制直接抖成筛子。
这里我画了一张图,帮你理清关系:
注意:不要以为选了PREEMPT_RT就万事大吉。我曾经在一个项目里,明明打了PREEMPT_RT补丁,延迟还是飙到500us。查了半天,发现是某个驱动在中断上下文里调用了kmalloc。嗯,驱动代码也得跟着改。
3.4 我的实战建议
如果你刚开始接触PREEMPT_RT,我建议你:
- 先跑主线内核的PREEMPT,看看延迟能不能接受
- 如果不行,再上PREEMPT_RT,但要做好驱动适配的准备
- 用cyclictest测延迟,这是最直观的工具
- 关注内核版本,5.10以上对PREEMPT_RT支持更好
我记得有一次,一个客户非要在3.10内核上打PREEMPT_RT补丁。我劝了半天没用,结果折腾了两周,各种冲突。最后换了4.19内核,一天搞定。所以,选对内核版本很重要。
好了,PREEMPT_RT的基本情况就是这样。下一节我们聊聊怎么实际打补丁、配置内核,那才是真正动手的时候。
公众号:蓝海资料掘金营,微信deep3321