Linux0.11內核中的wait_on_buffer和wait_on_inode函數是非常有代表性的延遲性函數處理過程,網上關於這兩個函數的討論
也很多,最主要的一個問題是爲什麼要在判斷b_lock之前關中斷,這個問題也困擾了我很長時間,查了不少帖子,學到不少東西,但總是
覺得有些細節沒有弄清楚,因此藉着自己實踐開發一個小OS的過程,研究了一下wait_on_buffer,還是學到不少東西的。貼出來,分享
給大家,歡迎討論~
Linux0.11版函數定義:
static inline void wait_on_buffer(struct buffer_head * bh)
{
cli();
while (bh->b_lock)
sleep_on(&bh->b_wait);
sti();
}
分析如下:
1. 首先可以明確,wait_on_buffer是工作在內核態的函數。更進一步應當理解爲兩種可能性:
或者是當前某個用戶態的進程請求數據進而引發的,那麼可以認爲是當前進程進入了內核態;又或者是內核本身的某個任務
引發的操作。不管怎樣wait_on_buffer背後是代表這某個進程或者任務的。
2. wait_on_buffer中通過cli和sti起到一個保護臨界區的作用,爲什麼這麼說?
原因首先還在於wait_on_buffer是工作在內核態的環境下,此時cli就意味着關閉了所有的可屏蔽中斷,如時鐘中斷和硬盤
處理中斷等等,這也就意味着:
1)當前工作在用戶態的進程不會因爲時間片到了有可能被輪轉出去,切換成其他的進程,從而保證while(bh->b_lock)形成的
若干條指令中間不會被打斷,造成可能有別的進程修改了bh->b_lock的值,造成錯誤;
2)不會造成硬盤中斷的到來引發的其他進程對bh->b_lock的操作,進而造成錯誤。
因此,通過關閉中斷,可以達到while (bh->b_lock)語句在執行期間被他人修改,從而實現臨界區的效果。
關於這一點,第3版的《Understanding the Linux Kernel》在第五章(內核同步)裏明確也提到,確保一組內核語句被當作
一個臨界區處理的主要機制之一就是中斷禁止,可惜本人在上學時學的OS教材是理論性較強的那種,只關注了各種各樣的臨界操
作模型,沒有提到實現機制,導致很長時間都覺得臨界區的概念很虛,不好掌握。
3. 還有一個重要的問題就是如果關閉了中斷,那別的用戶進程怎麼辦?是不是整個系統在這段時間內都不能收到相關的中斷信號
了?這個問題也有很多人問,答案當然是不會影響其他的用戶進程,原因在於sleep_on在將當前進程掛起後,會執行一次進程調
度操作,即schedule(),而一旦選擇了新進程進行切換時,會將新進程的EFLAGS寄存器內容也加載到相應的寄存器的,而這裏當
然包含了IF(Interrupt Flag)位,也就是說如果此時切換過來的進程是使用自己原先的中斷開關狀態的,原來的開就開,原來的關
就關,和之前的進程無關。因此,wait_on_buffer裏對中斷的操作,隻影響當時的進程,故這個中斷也被稱爲“本地中斷”,這
個稱呼更能反映其實質吧。