local_bh_disable
函数的每CPU更改量(在x86和最新内核的情况下)为__preempt_count
或current_thread_info()->preempt_count
。
无论如何,这都会给我们宽限期,因此我们可以假设在rcu_read_lock()
内执行local_bh_disable()
是多余的。实际上:in earlier kernels we can see local_bh_disable()
用于RCU,rcu_dereference()
随后在例如dev_queue_xmit
函数。后来local_bh_disable()
被rcu_read_lock_bh()
所取代,这最终变得比仅调用local_bh_disable()
更为复杂。现在看起来像这样:
static inline void rcu_read_lock_bh(void)
{
local_bh_disable();
__acquire(RCU_BH);
rcu_lock_acquire(&rcu_bh_lock_map);
RCU_LOCKDEP_WARN(!rcu_is_watching(),"rcu_read_lock_bh() used illegally while idle");
}
也有足够的文章描述RCU API。 Here我们可以看到:
您是否需要对待NMI处理程序,hardirq处理程序, 和禁用了抢占的代码段(是否 通过preempt_disable(),local_irq_save(),local_bh_disable(), 或其他某种机制),就像他们是显式RCU读者一样? 如果是这样,RCU调度是唯一适合您的选择。
这告诉我们在这种情况下使用 RCU Sched API ,因此rcu_dereference_sched()
应该会有所帮助。通过this comprehensive table,我们可以认识到rcu_dereference()
仅应在rcu_read_lock
/ rcu_read_unlock
标记内使用。
但是,它还不够清楚。我可以在rcu_dereference()
/ local_bh_disable
标记内使用local_bh_enable
(在现代内核的情况下)而不会误会什么吗?
P.S。就我而言,我无法将调用local_bh_disable
的代码更改为例如rcu_read_lock_bh
,因此我的代码在bh已禁用的情况下运行。还使用常规的RCU API。因此,它充满了rcu_read_lock
嵌套在local_bh_disable
中。
答案 0 :(得分:3)
您不应该混合使用API。如果需要使用RCU-bh API,则需要使用rcu_dereference_bh
。
您可以看到,如果在rcu_dereference_check
之后调用rcu_read_lock_bh
,它将正确地推测为not called in a RCU read-side critical section;在上面的代码段中,将对lock_is_held(&rcu_lock_map)
的呼叫与rcu_lock_acquire(&rcu_bh_lock_map);
进行对比。
RCU here的内核文档(在“ rcu_dereference()”部分中搜索)给出了正确用法的明确示例;只有在相应的rcu_dereference*
函数完成后才能正确调用rcu_read_lock*
。