每个CPU的local_bh_disable
-函数都会改变(对于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()
复杂一些。现在看起来是这样的:
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 SCHED是你唯一的选择。
这告诉我们在这种情况下使用rcu sched api,所以
rcu_read_lock_bh()
应该会有帮助。从this comprehensive table我们可以意识到local_bh_disable()
应该只在rcu_dereference_sched()
/rcu_dereference()
-标记中使用。然而,这还不够清楚。我能在不怀疑任何错误的情况下使用(在现代内核的情况下)内部的标记吗?
P.S.在我的例子中,我不能将代码调用
rcu_read_lock
改为调用例如rcu_read_unlock
,因此我的代码在bh已禁用的情况下运行。还使用了常用的rcu api。因此,它充满了嵌套在rcu_dereference()
中的local_bh_disable
。 最佳答案
您不应该混合和匹配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);
进行对比。
rcuhere的内核文档(搜索“rcu dereference()”一节)给出了正确用法的一个明确示例;只有在相应的rcu_dereference*
函数完成后才能正确调用rcu_read_lock*
。