Linux系統的中斷、系統調用和調度概述【轉】


最近學習Linux操作系統,關於中斷系統調用和進程的級別總是感覺有些模糊的地方,特在此做個小結,整理下思路。

所謂的中斷就是在計算機執行程序的過程中,由於出現了某些特殊事情,使得CPU暫停對程序的執行,轉而去執行處理這一事件的程序。等這些特殊事情處理完之后再回去執行之前的程序。中斷一般分為三類:1、由計算機硬件異常或故障引起的中斷,稱為內部異常中斷;2、由程序中執行了引起中斷的指令而造成的中斷,稱為軟中斷(這也是和我們將要說明的系統調用相關的中斷);3、由外部設備請求引起的中斷,稱為外部中斷。簡單來說,對中斷的理解就是對一些特殊事情的處理。

與中斷緊密相連的一個概念就是中斷處理程序了。當中斷發生的時候,系統需要去對中斷進行處理,對這些中斷的處理是由操作系統內核中的特定函數進行的,這些處理中斷的特定的函數就是我們所說的中斷處理程序了。

另一個與中斷緊密相連的概念就是中斷的優先級。中斷的優先級說明的是當一個中斷正在被處理的時候,處理器能接受的中斷的級別。中斷的優先級也表明了中斷需要被處理的緊急程度。每個中斷都有一個對應的優先級,當處理器在處理某一中斷的時候,只有比這個中斷優先級高的中斷可以被處理器接受並且被處理。優先級比這個當前正在被處理的中斷優先級要低的中斷將會被忽略。

典型的中斷級如下所示

當發生軟件中斷時,其他所有的中斷都可能發生並被處理;但當發生磁盤中斷時,就只有時鍾中斷和機器錯誤中斷能被處理了。

在講系統調用之前,先說下進程的執行在系統上的兩個級別:用戶級和核心級,也稱為用戶態和系統態(user mode  and kernel mode)。程序的執行一般是在用戶態下執行的,但當程序需要使用操作系統提供的服務時,比如說打開某一設備、創建文件、讀寫文件等,就需要向操作系統發出調用服務的請求,這就是系統調用。Linux系統有專門的函數庫來提供這些請求操作系統服務的入口,這個函數庫中包含了操作系統說提供的對外服務的接口。當進程發出系統調用之后,它所處的運行狀態就會由用戶態變成核心態。但這個時候,進程本身其實並沒有做什么事情,這個時候是由內核在做相應的操作,去完成進程所提出的這些請求。

系統調用和中斷的關系就在於,當進程發出系統調用申請的時候,會產生一個軟件中斷。產生這個軟件中斷以后,系統會去對這個軟中斷進行處理,這個時候進程就處於核心態了。

那么用戶態和核心態之間的區別是什么呢?(以下區別摘至《UNIX操作系統設計》)

1、用戶態的進程能存取它們自己的指令和數據,但不能存取內核指令和數據(或其他進程的指令和數據)。然而,核心態下的進程能夠存取內核和用戶地址

2、某些機器指令是特權指令,在用戶態下執行特權指令會引起錯誤

對此要理解的一個是,在系統中內核並不是作為一個與用戶進程平行的估計的進程的集合,內核是為用戶進程運行的。

如何去理解上面所說的區別,特別是區別1呢?真正理解這點,需要對進程在內存中的表示有個大致的理解。

每個程序需要被裝入(全部或部分)裝入內存后才能開始運行,在32位機器中,每個進程都有4G的虛擬地址空間。但是對這4G的空間並不是全部都可以被進程使用的,在Linux中,對這4G的空間的大致划分如下

因此,從原則上來說,在進程中用戶能使用的虛擬地址空間是只有3G的。正常情況下,用戶程序在用戶態運行的時候,只能訪問在這3G范圍內的地址(當然也不是所有地址都能訪問)。當進程由於系統調用而進入核心態時,這時系統內核會執行相應的操作,它能訪問自己1G的地址空間,同時也能訪問3G的用戶地址空間。而用戶進程的指令的數據是存在與那3G的地址空間中的。當然還有進程的棧等部分。

細分來說的話,一個進程在內存中一般包含以下部分,數據段、指令段、運行時堆、棧等。示意圖如下

內核自己的棧這在最上層的1G的地址空間內,這是只能由內核訪問的部分。

 

在說進程調度之前,首先整理下進程可能的各種狀態。首先我們知道進程的運行狀態是分為核心態和用戶態。其他的進程狀態包括如下

進程未被執行,但出於就緒狀態,只要內核調度它,即可執行

進程正在睡眠中並且存在主存中

進程處於就緒狀態,但處在二級存儲器中

進程在睡眠中,且在二級存儲器中

進程執行完核心態的操作,正要返回用戶態時,內核做了進程調度,切換了上下文

進程剛被創建

進程調用了exit,處於僵死狀態

進程之間的狀態轉換示意圖如下,箭頭指明了轉換的方向

進程的各種狀態的轉換比較復雜,這里主要關注進程的兩個運行狀態、睡眠以及從就緒到運行的轉換

從示意圖中可以看出,當發生中斷或者系統調用時,進程由用戶態轉成核心態。但進程在核心態運行時,是不能被搶占的,因此只有當進程由核心態進入睡眠狀態時,或者進程處於用戶態時,內核才允許做進程調度,切換上下文。而處於就緒狀態的進程當被內核調度開始運行的時候,首先是進入核心態的。

那么為什么,進程在核心態運行的時候,不允許做進程調度呢?因為在核心態運行的時候,需要訪問一些全局核心數據結構中的信息。如果運行在核心態時的進程調度,那么會改變內核運行時的進程上下文,而這些不同的進程上下文對同一個核心數據可能會有不同的操作要求,這樣將有可能會破壞全局核心數據結構中的信息。為了保證內核核心數據的一致性,當進程處於核心態時,是不允許進行上下文切換的。

這就涉及到另一個問題,中斷是在任何時刻都能發生的,並且對中斷的處理也可能影響內核數據的一致性。那么,但進程在核心態運行時,對於發生中斷的情況又如何保證內核數據的一致性呢?解決的方法大致分為兩類,一種是簡單地在核心態時,禁止所有的中斷,但這樣會降低對中斷的響應速度;另一種方法是設立臨界區,找出操作語句中可能會導致內核數據不一致的地方,然后將這部分設為臨界區。但CPU執行臨界區代碼時,把CPU的執行級別提高,這樣就可以屏蔽掉很多的中斷,從而保證數據的一致性了。一般,為了保證系統的性能,臨界區都很小,並且不會經常出現。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM