如何保护 RCU reader 部分不被抢占?
How RCU reader section is protected from preemption?
(来自 LWN 上的一篇文章)
1 rcu_read_lock();
2 list_for_each_entry_rcu(p, head, list) {
3 do_something_with(p->a, p->b, p->c);
4 }
5 rcu_read_unlock();
RCU 更新操作将执行 synchronize_rcu() 以断言每个 CPU 已切换上下文,因此每个 RCU-reader 已完成其工作。但是RCU必须依赖reader不被抢占。事实上,LWN 接下来说:
Although this simple approach works for kernels in which preemption is
disabled across RCU read-side critical sections, in other words, for
non-CONFIG_PREEMPT and CONFIG_PREEMPT kernels, it does not work for
CONFIG_PREEMPT_RT realtime (-rt) kernels.
我知道 non-CONFIG_PREEMPT 内核禁用抢占,但为什么 CONFIG_PREEMPT 内核也可以?
我们需要 CONFIG_PREEMPT 内核的 RCU。如果没有抢占或阻塞,那么我们就不会陷入这种同步混乱之中。有两种类型的 RCU 实现:
1) Non-preemptible RCU implementation
2) Preemptible RCU implementation
当在一个 CPU 上调用 synchronize_rcu() 而在其他 CPU 上调用时
在 RCU 读端临界区内,则
synchronize_rcu() 保证阻塞直到所有其他
CPUs 退出了它们的临界区。同样,如果 call_rcu() 被调用
在一个 CPU 上,而其他 CPU 在 RCU 读端临界范围内
部分,延迟调用相应的 RCU 回调
直到所有其他 CPU 退出它们的临界区。
在不可抢占的 RCU 实现中,在 RCU 读端临界区中阻塞是非法的。
CONFIG_PREEMPT 中的抢占式 RCU 实现 (PREEMPT_RCU)
内核构建,RCU 读端临界区可能被抢占,
但明确阻止是非法的。最后,在抢占式 RCU 中
实时实现(使用 -rt 补丁集)内核构建,RCU
读端临界区可能被抢占,它们也可能阻塞,但是
仅在获取受优先级继承约束的自旋锁时。
在 CONFIG_PREEMPT 内核上是可以的,因为在任务被抢占之前注意完成 rcu 读取临界区。调度程序检查当前任务是否在 rcu 读取临界区中,如果是,它会提高其优先级以完成临界区。有关详细信息,请参阅本文:http://lwn.net/Articles/220677/
(来自 LWN 上的一篇文章)
1 rcu_read_lock();
2 list_for_each_entry_rcu(p, head, list) {
3 do_something_with(p->a, p->b, p->c);
4 }
5 rcu_read_unlock();
RCU 更新操作将执行 synchronize_rcu() 以断言每个 CPU 已切换上下文,因此每个 RCU-reader 已完成其工作。但是RCU必须依赖reader不被抢占。事实上,LWN 接下来说:
Although this simple approach works for kernels in which preemption is disabled across RCU read-side critical sections, in other words, for non-CONFIG_PREEMPT and CONFIG_PREEMPT kernels, it does not work for CONFIG_PREEMPT_RT realtime (-rt) kernels.
我知道 non-CONFIG_PREEMPT 内核禁用抢占,但为什么 CONFIG_PREEMPT 内核也可以?
我们需要 CONFIG_PREEMPT 内核的 RCU。如果没有抢占或阻塞,那么我们就不会陷入这种同步混乱之中。有两种类型的 RCU 实现:
1) Non-preemptible RCU implementation
2) Preemptible RCU implementation
当在一个 CPU 上调用 synchronize_rcu() 而在其他 CPU 上调用时 在 RCU 读端临界区内,则 synchronize_rcu() 保证阻塞直到所有其他 CPUs 退出了它们的临界区。同样,如果 call_rcu() 被调用 在一个 CPU 上,而其他 CPU 在 RCU 读端临界范围内 部分,延迟调用相应的 RCU 回调 直到所有其他 CPU 退出它们的临界区。
在不可抢占的 RCU 实现中,在 RCU 读端临界区中阻塞是非法的。 CONFIG_PREEMPT 中的抢占式 RCU 实现 (PREEMPT_RCU) 内核构建,RCU 读端临界区可能被抢占, 但明确阻止是非法的。最后,在抢占式 RCU 中 实时实现(使用 -rt 补丁集)内核构建,RCU 读端临界区可能被抢占,它们也可能阻塞,但是 仅在获取受优先级继承约束的自旋锁时。
在 CONFIG_PREEMPT 内核上是可以的,因为在任务被抢占之前注意完成 rcu 读取临界区。调度程序检查当前任务是否在 rcu 读取临界区中,如果是,它会提高其优先级以完成临界区。有关详细信息,请参阅本文:http://lwn.net/Articles/220677/