C语言 在 local_bh_disable()/local_bh_enable() 中使用 rcu_dereferen



每个cpu 的local_bh_disable函数更改(在 x86 和最近的内核的情况下)__preempt_countcurrent_thread_info()->preempt_count否则。

无论如何,这给了我们一个宽限期,因此我们可以假设在local_bh_disable()内部执行rcu_read_lock()是多余的。事实上:在前面的内核中,我们可以看到local_bh_disable()用于 RCU,随后在dev_queue_xmit-函数中调用rcu_dereference()。后来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。在这里我们可以看到:

您是否需要治疗NMI处理程序,hardirq处理程序, 和禁用抢占的代码段(是否 通过 preempt_disable(), local_irq_save(), local_bh_disable(), 或其他机制)就好像他们是明确的 RCU 读取器一样? 如果是这样,RCU-sched 是唯一适合您的选择。

这告诉我们在这种情况下使用RCU Sched API,因此rcu_dereference_sched()应该有所帮助。从这个综合表中,我们可以意识到rcu_dereference()应该只在rcu_read_lock/rcu_read_unlock标记中使用。

但是,还不够清楚。我可以在local_bh_disable/local_bh_enable标记中使用(在现代内核的情况下)rcu_dereference()而不会出错吗?

附言就我而言,我无法更改调用local_bh_disable的代码,例如rcu_read_lock_bh,所以我的代码在已经禁用 bh 的情况下运行。还使用了通常的 RCU API。因此,它充满了嵌套在local_bh_disable中的rcu_read_lock

您不应该混合搭配 API。如果需要使用 RCU-bh API,则需要使用rcu_dereference_bh

您可以看到,如果您在rcu_read_lock_bh之后调用rcu_dereference_check,它会正确推测它不是在 RCU 读取端关键部分中调用的;将对lock_is_held(&rcu_lock_map)的调用与上面代码段中的rcu_lock_acquire(&rcu_bh_lock_map);进行对比。

此处 RCU 的内核文档(搜索"rcu_dereference()"部分)给出了正确用法的明确示例; 只有在相应的rcu_read_lock*函数完成后才能正确调用rcu_dereference*

相关内容

  • 没有找到相关文章

最新更新