Linux RT 分析Linux 6.12.107

08 · RCU:可抢占读端、优先级提升与线程化回调

结论:PREEMPT_RT 选中 PREEMPTION 后自动得到 PREEMPT_RCU(读端可抢占,甚至可在 PI 锁上睡眠)、RCU_BOOST 默认开(rcub/N 线程在宽限期开始 500 ms 后提升被抢占的读者)、use_softirq 固定为 0(回调在 rcuc/N SCHED_FIFO 1 线程执行,且启动参数不注册)、rcu_normal_after_boot 固定为 1(启动后禁止加急宽限期,不再向所有 CPU 发 IPI)。收益:RCU 读区与回调不再是不可抢占区,也不再有 IPI 打断隔离 CPU;代价:宽限期变长、内存回收滞后、synchronize_rcu_expedited() 变慢,并且 RT 任务长期霸占 CPU 且优先级高于 1 时会造成 RCU stall。

第一层

先看结论:RT 让 RCU 读端可抢占、回调进线程、被阻塞的读者 500 ms 后被提升、启动后禁止加急宽限期——读区与回调都不再制造延迟,代价是宽限期更长。

非 RT读端关抢占,回调在 RCU_SOFTIRQ
非 RT:读端关抢占,回调在 RCU_SOFTIRQ
同一场景 · 换成 PREEMPT_RT 内核
PREEMPT_RT读端可抢占 + RCU_BOOST + rcuc 线程 + 禁加急 GP
RT:读端可抢占 + RCU_BOOST + rcuc 线程 + 禁加急 GP

第二层

先看结论:四个 Kconfig 默认值(PREEMPT_RCU/RCU_BOOST/RCU_NOCB_CPU_CB_BOOST/RCU_EXP_KTHREAD)加两个编译期常量(use_softirq=0rcu_normal_after_boot=1)决定了一切。

非 RTTree RCU 宽限期与回调流水线
非 RT:Tree RCU 宽限期与回调流水线
同一场景 · 换成 PREEMPT_RT 内核
PREEMPT_RTKconfig 联动、boost 线程、rcuc、rcu_normal_after_boot
RT:Kconfig 联动、boost 线程、rcuc、rcu_normal_after_boot

Kconfig 联动(kernel/rcu/Kconfig

符号 非 RT RT 位置
PREEMPT_RCU default y if PREEMPTION(PREEMPT/DYNAMIC 内核也有) y :19-22
RCU_BOOST RT_MUTEXES && PREEMPT_RCU && RCU_EXPERT default y if PREEMPT_RT,无需 EXPERT :198-206
RCU_BOOST_DELAY 500 ms 500 ms :211-220
RCU_EXP_KTHREAD default !PREEMPT_RT && NR_CPUS <= 32 默认关(加急 GP 启动后被禁) :224-234
RCU_NOCB_CPU default n default n(推荐手动开 + rcu_nocbs= :238-256
RCU_NOCB_CPU_CB_BOOST 需手动 default y if PREEMPT_RT:offload 回调用 SCHED_FIFO :279-293
TASKS_TRACE_RCU_READ_MB NR_CPUS < 8 default PREEMPT_RT:读端用内存屏障代替 IPI :295-298

读端

include/linux/rcupdate.h:70-101:PREEMPT_RCU 下 __rcu_read_lock() 是 out-of-line 的嵌套计数,不关抢占;非抢占 RCU 下就是 preempt_disable():836-843 的文档分三档:非抢占 RCU 读区不能阻塞;PREEMPT_RCU 读区可被抢占但不能显式阻塞;RT 读区可被抢占、也可以阻塞——但只允许阻塞在受 PI 保护的自旋锁上Documentation/RCU/whatisRCU.rst:177-179:RT 下 spin_lock() 隐含进入 RCU 读区(rt_spin_lock() 里的 rcu_read_lock(),第 02 章)。

被抢占的读者记入 rnp->blkd_tasksrcu_read_unlock_special()kernel/rcu/tree_plugin.h:705-746)在关中断状态退出读区时需要 expedited 处理以及时 deboost,:746 那行 use_softirq && … 是 RT/非 RT 的分叉。

回调执行:softirq → rcuc 线程

kernel/rcu/tree.c:105-109

static bool use_softirq = !IS_ENABLED(CONFIG_PREEMPT_RT);
#ifndef CONFIG_PREEMPT_RT
module_param(use_softirq, bool, 0444);
#endif

RT 上参数根本不注册(Documentation/admin-guide/kernel-parameters.txt:5214-5222 也这么写)。invoke_rcu_core():2877-2885)据此选择 raise_softirq(RCU_SOFTIRQ) 或唤醒 rcuc/Nrcu_cpu_kthread():2897-2933)每次最多 10 轮,每轮 local_bh_disable() 包裹,然后 schedule_timeout_idle(2)

优先级:kthread_prio = IS_ENABLED(CONFIG_RCU_BOOST) ? 1 : 0:163-169),rcuc/rcub/GP 线程都设为 SCHED_FIFO kthread_priotree_plugin.h:1112-1126, 1301-1322tree.c:5393-5396),rcutree.kthread_prio= 可调(sanitize_kthread_prio() :5541-5558 钳到 1–99)。启动日志会打印 "RCU_SOFTIRQ processing moved to rcuc kthreads" 与 "RCU priority boosting: priority 1 delay 500 ms"。

优先级提升

rcu_boost_kthreadtree_plugin.h:1217-1220)每个叶子 rcu_node 一个,boost_time = GP 开始 + RCU_BOOST_DELAY_JIFFIES:1287-1294);到点后通过 rt_mutex 把最老的阻塞读者提升到 kthread_prio。加急 GP 阻塞的读者立即提升(Kconfig:219-220)。

禁止加急宽限期

kernel/rcu/update.c:60-62rcu_normal_after_boot = IS_ENABLED(CONFIG_PREEMPT_RT),RT(无 NO_HZ_FULL)下参数不暴露。所有 synchronize_rcu_expedited() 启动后降级为普通 GP(kernel-parameters.txt:5595-5600)——不再有 IPI 广播,但模块卸载、网络命名空间销毁、部分 sysfs 操作会明显变慢。

与 softirq 的其它交叉

ARM64 注

性能影响

净影响:无 IPI 打断隔离 CPU;kfree_rcu 回收滞后、expedited 变慢;RT 任务长跑且优先级 > 1 会导致 stall。

指标 非 RT RT 说明
读区对最坏延迟的贡献 非抢占 RCU:整段 ≈ 0
回调执行 softirq 就地,零切换 rcuc 线程,可被抢占 多一次切换;RT 任务可压住它
宽限期长度 短(读者不可抢占) 长(读者可被抢占很久,500 ms 后才 boost) kfree_rcu 内存回收滞后,内存压力上升
加急 GP ms 级完成,IPI 打断所有 CPU 降级为普通 GP:数十 ms – 数百 ms 模块卸载/命名空间销毁变慢
隔离 CPU 被 IPI 打断 不会(加急被禁 + TASKS_TRACE_RCU_READ_MB RT 的隔离收益
stall 风险 RT 任务 > prio 1 且长跑时高 rcu_nocbs + 提高 kthread_prio 或让出 CPU

源码定位

主题 位置
Kconfig kernel/rcu/Kconfig:8-34, 143-170, 198-298
use_softirq / invoke_rcu_core / rcuc kernel/rcu/tree.c:105-109, 2877-2958
kthread_prio kernel/rcu/tree.c:163-169, 4928, 4959, 5393-5396, 5541-5558
boost 线程 kernel/rcu/tree_plugin.h:1112-1126, 1217-1220, 1287-1322
读端 include/linux/rcupdate.h:70-101, 832-843kernel/rcu/tree_plugin.h:705-746
rcu_normal_after_boot kernel/rcu/update.c:60-62, 667-668
文档 Documentation/admin-guide/kernel-parameters.txt:5214-5222, 5595-5600Documentation/RCU/stallwarn.rst:56-60Documentation/RCU/whatisRCU.rst:177-179

调优要点

小结