一、前言
中斷發生以后,CPU跳到內核設置好的中斷處理代碼中去,由這部分內核代碼來處理中斷。這個處理過程中的上下文就是中斷上下文。
為什么可能導致睡眠的函數都不能在中斷上下文中使用呢?
首先睡眠的含義是將進程置於“睡眠”狀態,在這個狀態的進程不能被調度執行。然后,在一定的時機,這個進程可能會被重新置為“運行”狀態,從而可能被調度執行。 可見,“睡眠”與“運行”是針對進程而言的,代表進程的task_struct結構記錄着進程的狀態。內核中的“調度器”通過task_struct對進程進行調度。
但是,中斷上下文卻不是一個進程,它並不存在task_struct,所以它是不可調度的。所以,在中斷上下文就不能睡眠。
那么,中斷上下文為什么不存在對應的task_struct結構呢?
中斷的產生是很頻繁的(至少每毫秒(看配置,可能10毫秒或其他值)會產生一個時鍾中斷),並且中斷處理過程會很快。如果為中斷上下文維護一個對應的task_struct結構,那么這個結構頻繁地分配、回收,並且影響調度器的管理,這樣會對整個系統的吞吐量有所影響。
但是在某些追求實時性的嵌入式linux中,中斷也可能被賦予task_struct結構。這是為了避免:如果出現大量中斷不斷的嵌套的情況,導致一段時間內CPU總是運行在中斷上下文,使得某些優先級非常高的進程得不到運行。這種做法能夠提高系統的實時性,但是代價中吞吐量的降低。
二、詳解
內核空間和用戶空間是現代操作系統的兩種工作模式,內核模塊運行在內核空間,而用戶態應用程序運行在用戶空間。它們代表不同的級別,而對系統資源具有不同的訪問權限。內核模塊運行在最高級別(內核態),這個級下所有的操作都受系統信任,而應用程序運行在較低級別(用戶態)。在這個級別,處理器控制着對硬件的直接訪問以及對內存的非授權訪問。內核態和用戶態有自己的內存映射,即自己的地址空間。
處理器總處於以下狀態中的一種:
- 內核態,運行於進程上下文,內核代表進程運行於內核空間;
- 內核態,運行於中斷上下文,內核代表硬件運行於內核空間;
- 用戶態,運行於用戶空間。
也就是說,用戶態不能訪問內核地址空間的內存,也不能直接訪問硬件。要想這么做,一個通過系統調用進入內核態,也就產生了進程上下文;一個通過中斷訪問硬件,也就產生了中斷上下文。兩種狀態的切換對應不同的目的(一個訪問硬件,一個使用系統調用),有不同的來源(一個使用系統調用進入,一個使用硬件中斷進入)。
用戶空間的應用程序,通過系統調用,進入內核空間。由內核代表該進程運行於內核空間,這就涉及到上下文的切換,用戶空間和內核空間具有不同的地址映射、通用或專用的寄存器組,而用戶空間的進程要傳遞很多變量、參數給內核,內核也要保存用戶進程的一些寄存器、變量等,以便系統調用結束后回到用戶空間繼續執行。
上下文context:上下文簡單說來就是一個環境,相對於進程而言,就是進程執行時的環境。具體來說就是各個變量和數據,包括所有的寄存器變量、進程打開的文件、內存信息等。
所謂“進程上下文”,就是一個進程在執行的時候,CPU的所有寄存器中的值、進程的狀態以及堆棧上的內容,當內核需要切換到另一個進程時,它需要保存當前進程的所有狀態,即保存當前進程的進程上下文,以便再次執行該進程時,能夠恢復切換時的狀態,繼續執行。
所謂“中斷上下文”,就是硬件通過觸發信號,導致內核調用中斷處理程序,進入內核空間。這個過程中,硬件的一些變量和參數也要傳遞給內核,內核通過這些參數進行中斷處理。中斷上下文,其實也可以看作就是硬件傳遞過來的這些參數和內核需要保存的一些其他環境(主要是當前被中斷的進程環境)。
當一個進程在執行時,CPU的所有寄存器中的值、進程的狀態以及堆棧中的內容被稱為該進程的上下文。當內核需要切換到另一個進程時,它需要保存當前進程的所有狀態,即保存當前進程的上下文,以便在再次執行該進程時,能夠得到切換時的狀態執行下去。在LINUX中,當前進程上下文均保存在進程的任務數據結構中。在發生中斷時,內核就在被中斷進程的上下文中,在內核態下執行中斷服務例程。但同時會保留所有需要用到的資源,以便中繼服務結束時能恢復被中斷進程的執行。
Linux內核工作在進程上下文或者中斷上下文。提供系統調用服務的內核代碼代表發起系統調用的應用程序運行在進程上下文;另一方面,中斷處理程序,異步運行在中斷上下文。中斷上下文和特定進程無關。
一個進程的上下文可以分為三個部分:用戶級上下文、寄存器上下文以及系統級上下文。
用戶級上下文: 正文、數據、用戶堆棧以及共享存儲區;
寄存器上下文: 通用寄存器、程序寄存器(IP)、處理器狀態寄存器(EFLAGS)、棧指針(ESP);
系統級上下文: 進程控制塊task_struct、內存管理信息(mm_struct、vm_area_struct、pgd、pte)、內核棧。
當發生進程調度時,進行進程切換就是上下文切換(context switch)。操作系統必須對上面提到的全部信息進行切換,新調度的進程才能運行。而系統調用進行的是模式切換(mode switch)。模式切換與進程切換比較起來,容易很多,而且節省時間,因為模式切換最主要的任務只是切換進程寄存器上下文的切換。
進程上下文主要是異常處理程序和內核線程。內核之所以進入進程上下文是因為進程自身的一些工作需要在內核中做。例如,系統調用是為當前進程服務的,異常通常是處理進程導致的錯誤狀態等。所以在進程上下文中引用current是有意義的。
http://blog.csdn.net/yusiguyuan/article/details/12183743