为何spin_unlock_bh函数启用抢占却不调用调度器?
Spinlock Unlock Behavior in Linux Kernel 3.10.1: Why
spin_unlock_bh() Uses preempt_enable_no_resched() Great question—this digs into some really nuanced design choices around spinlocks and kernel context management. Let’s break down why this behavior exists:
First, let’s recap what each lock/unlock pair actually does:
spin_lock_bh()doesn’t just grab the spinlock—it also callslocal_bh_disable()(disables softirqs like tasklets or bottom halves) andpreempt_disable()(turns off kernel preemption). This is specifically for code paths that might be interrupted by softirqs, and need to block both preemption and softirq interference.spin_lock()only disables preemption, whilespin_lock_irq()disables both hardware interrupts and preemption.
Now, the key difference in their unlock counterparts:
- For
spin_unlock()andspin_unlock_irq(), using regularpreempt_enable()makes sense because these paths return to a "normal" process context where immediate preemption is safe and desirable. If a higher-priority task is waiting, triggering__schedule()right away keeps the system responsive. - But
spin_unlock_bh()has to handle a critical edge case: we might be returning from a softirq context (or just re-enabling softirqs in process context). Softirq contexts can’t be preempted—they run to completion without scheduling. When you calllocal_bh_enable()as part ofspin_unlock_bh(), any pending softirqs will run immediately after the unlock. If we used regularpreempt_enable()here, it could trigger a schedule right in the middle of softirq processing, which is unsafe and breaks kernel context rules.
Using preempt_enable_no_resched() solves this perfectly:
- It marks preemption as allowed again, but skips the immediate call to
__schedule(). - The scheduler will still get a chance to run at the next valid scheduling point (like when returning to user space, or after any pending softirqs finish executing).
- This ensures that softirqs get processed first, and we don’t introduce unexpected context switches in a context where they aren’t allowed.
To sum it up: spin_unlock_bh()’s design prioritizes safely re-enabling softirqs and deferring scheduling until a safe moment, whereas the other unlock functions can safely trigger scheduling immediately because they aren’t dealing with softirq context constraints.
内容的提问来源于stack exchange,提问作者Haris
相关产品推荐
相关产品推荐

