對於Linux內核重入我做了一下一些分析。
首先要界定一個范圍(代碼段,函數)然後才可以討論重入。
比如以函數A,B分別為一個范圍。在運行A的時候發生中斷,調用B,B運行完了又返回A,這個時候稱B進入A.
如果A=B,那麼稱A重入A,或者可以說有兩個A的實例在運行。
重入導致的問題主要就是由於這兩個A可以會幾乎同時訪問一些堆中的變量而出現不一致。解決這個問題的辦法有幾個:
干脆不允許某個函數(某段代碼)重入,也就是如果A運行,當發生中斷的時候,調用A,發現已經有A運行了,則返回,不再運行這個新的A.bottom half采用這個辦法。
或者對一些臨界區上鎖。
或者干脆關中斷。
內核的重入,首先界定的范圍就是整個處於內核級的代碼段。
因此,內核的重入可以說是經常發生的,比如中斷發生時。
內核的重入有兩種情況:
1與進程無關的中斷發生時,CPU已經在內核中運行,也就是中斷嵌套。一般內核會做一定的保護,比如關中斷,鎖臨界區等。但是這種中斷有一個特點,就是先進後出的棧的模式,因此,用一個棧足矣。
2與進程相關的切換。如果總是在內核返回到用戶級代碼段時才切換,那麼這個意義上的重入就不存在,用一個內核棧就可以了。還有一種可能是在內核中就切換,由於進程執行並不是按照先進先出的模式,因此,每個進程都有一個內核棧。
還有一個問題,上面與進程無關的中斷一般訪問與進程無關的數據,所以需要保護的數據比較少。在這種重入中,幾個進程的內核實例會訪問與進程相關的共有數據,會導致不一致,而這種臨界區會比較多,所以上鎖可能會比較麻煩,Linux采用的是一種非透明的切換,即當前進程的內核部分必須主動放棄CPU,才可能切換。這樣使內核同步比較簡單。所以Linux內核的重入是一定條件下的重入,非搶占式的重入。
更多內容請看內核技術 系統管理專題,或