我正在研究内核代码(版本 3.10.1(的自旋锁代码,但有一件事不明白。
当通过函数spin_lock_bh()
获取自旋锁时,它会继续调用preempt_disable()
。这与用于获取(例如spin_lock()
和spin_lock_irq()
(的其他自旋锁函数相同。
但是当通过spin_unlock_bh()
释放锁时,它会调用preempt_enable_no_resched()
,这会跳过调用调度程序抢占。 其他相应的发布功能(如spin_unlock()
和spin_unlock_irq()
(并非如此。它们调用调用__schedule()
的常规preempt_enable()
函数。
local_bh_disable()
按特定值递增计数器preempt_count
也会preempt_disable()
递增1
。这就是__raw_spin_lock_bh()
所做的。
preempt_enable()
函数(从__raw_spin_unlock()
和__raw_spin_unlock_irq()
调用(调用preempt_check_resched()
。但是,当抢占仍处于禁用状态时,无需尝试进行计划。它将在函数退出时_local_bh_enable_ip()
内部完成。
查看源代码,您可以看到真正的"BH"自旋锁调用序列是:
spin_release(&lock->dep_map, 1, _RET_IP_);
do_raw_spin_unlock(lock);
preempt_enable_no_resched();
____barrier();
____dec_preempt_count(); // <--- decrease counter, but we can't schedule here
local_bh_enable_ip();
____sub_preempt_count() // <--- real disabling preemption
____preempt_check_resched(); // <--- schedule
但f.e. "IRQ" 自旋锁调用序列:
spin_release(&lock->dep_map, 1, _RET_IP_);
do_raw_spin_unlock(lock);
local_irq_enable();
preempt_enable();
____barrier();
____dec_preempt_count(); // <--- real disabling preemption
____barrier();
____preempt_check_resched(); // <--- schedule
总而言之:在BH自旋锁的情况下,它只是绕过preempt_check_resched()
因为它不是必需的。