spin_unlock_bh函数为什么不用调用调度器就可以抢占

Why does spin_unlock_bh function enables preemption without calling the scheduler

我正在查看内核代码(版本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() 内完成。

查看 source code you can see that the real "BH" spinlock 调用顺序是:

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" spinlock调用顺序:

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-spinlock 的情况下,它只是绕过 preempt_check_resched() 因为它不需要。