Linux內核spin_lock與spin_lock_irq分析

在Linux內核中何時使用spin_lock,何時使用spin_lock_irqsave很容易混淆。首先看一下代碼是如何實現的。

spin_lock的調用關係

     spin_lock

            |

           + ----->  raw_spin_lock

|

+------>  _raw_spin_lock

                         |

                        +--------> __raw_spin_lock

static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
        preempt_disable();
        spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
        LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}

spin_lock_irq的調用關係

    spin_lock_irq

                |

               +-------> raw_spin_lock_irq

                                           |

                                          +---------> _raw_spin_lock_irq

                                                                      |

                                                                      +------------> __raw_spin_lock_irq

static inline void __raw_spin_lock_irq(raw_spinlock_t *lock)
{
        local_irq_disable();
        preempt_disable();
        spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
        LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}

可以看出來他們兩者只有一個差別:是否調用local_irq_disable()函數, 即是否禁止本地中斷。

在任何情況下使用spin_lock_irq都是安全的。因爲它既禁止本地中斷,又禁止內核搶佔。

spin_lock比spin_lock_irq速度快,但是它並不是任何情況下都是安全的。

舉個例子:進程A中調用了spin_lock(&lock)然後進入臨界區,此時來了一箇中斷(interrupt),

該中斷也運行在和進程A相同的CPU上,並且在該中斷處理程序中恰巧也會spin_lock(&lock)

試圖獲取同一個鎖。由於是在同一個CPU上被中斷,進程A會被設置爲TASK_INTERRUPT狀態,

中斷處理程序無法獲得鎖,會不停的忙等,由於進程A被設置爲中斷狀態,schedule()進程調度就

無法再調度進程A運行,這樣就導致了死鎖!

但是如果該中斷處理程序運行在不同的CPU上就不會觸發死鎖。 因爲在不同的CPU上出現中斷不會導致

進程A的狀態被設爲TASK_INTERRUPT,只是換出。當中斷處理程序忙等被換出後,進程A還是有機會

獲得CPU,執行並退出臨界區。

所以在使用spin_lock時要明確知道該鎖不會在中斷處理程序中使用。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章