操做系統(三)

3.1 什麼是進程

3.1.1 背景

在給進程下定義以前,先總結一下第一、2章介紹的一些概念:算法

  • 一個計算機平臺包括一組硬件資源,好比處理器、內存、I/O 模塊、定時器和磁盤驅動器等。
  • 計算機程序是爲執行某些任務而開發的。在典型的狀況下,它們接受外來的輸入,作一些處理以後,輸出結果。
  • 直接根據給定的硬件平臺寫應用程序效率是低下的,主要緣由以下:
    • 針對相同的平臺能夠開發出不少應用程序,因此開發出這些應用程序訪問計算機資源的通用例程是頗有意義的。
    • 處理器自己只能對多道程序設計提供有限的支持,須要用軟件去管理處理器和其餘資源同時被多個程序共享。
    • 若是多個程序在同一時間都是活躍的,那麼須要保護每一個程序的數據、I/O 使用和其餘資源不被其餘程序佔用。
  • 開發操做系統是爲了給應用程序提供一個方便、安全和一致的接口。操做系統是計算機硬件和應用程序之間的一層軟件,對應用程序和工具提供了支持。
  • 能夠把操做系統想象爲資源的統一抽象表示,能夠被應用程序請求和訪問。資源包括內存、網絡接口和文件系統等。一旦操做系統爲應用程序建立了這些資源的抽象表示,就必須管理它們的使用,例如一個操做系統能夠容許資源共享和資源保護。

有了應用程序、系統軟件和資源的概念,就能夠討論操做系統怎樣以一個有序的方式管理應用程序的執行,以達到如下目的:數據庫

  • 資源對多個應用程序是可用的。
  • 物理處理器在多個應用程序間切換以保證全部程序都在執行中。
  • 處理器和I/O 設備能獲得充分的利用。

全部現代操做系統採用的方法都是依據對應於一個或多個進程存在的應用程序執行的一種模型。小程序

3.1.2 進程和進程控制塊

第2章給進程下了如下幾個定義:安全

  • 正在執行的程序。
  • 正在計算機上執行的程序實例。
  • 能分配給處理器並由處理器執行的實體。
  • 具備如下特徵的活動單元:一組指令序列的執行、一個當前狀態和相關的系統資源集。

也能夠把進程當成由一組元素組成的實體,進程的兩個基本的元素是程序代碼(可能被執行相同程序的其餘進程共享)和代碼相關聯的數據集。
假設處理器開始執行這個程序代碼,且把這個執行實體叫作進程。
在進程執行時,任意給定一個時間,進程均可以惟一地被表徵爲如下元素:服務器

  • 標識符:跟這個進程相關的惟一標識符,用來區別其餘進程。
  • 狀態:若是進程正在執行,那麼進程處於運行態。
  • 優先級:相對於其餘進程的優先級。
  • 程序計數器:程序中即將被執行的下一條指令的地址。
  • 內存指針:包括程序代碼和進程相關數據的指針,還有和其餘進程共享內存塊的指針。
  • 上下文數據:進程執行時處理器的寄存器中的數據。
  • I/O 狀態信息:包括顯式的I/O 請求、分配給進程的I/O 設備(例如磁帶驅動器)和被進程使用的文件列表等。
  • 記帳信息:可能包括處理器時間總和、使用的時鐘數總和、時間限制、記帳號等。

上述列表信息存放在一個叫作進程控制塊(如圖)的數據結構中,該控制塊由操做系統建立和管理。進程控制塊包含了充分的信息,這樣就能夠中斷一個進程的執行,而且在後來恢復執行進程時就好像進程未被中斷過。進程控制塊是操做系統可以支持多進程和提供多處理的關鍵工具。當進程被中斷時,操做系統會把程序計數器和處理器寄存器(上下文數據)保存到進程控制塊中的相應位置,進程狀態也被改變爲其餘的值,例如阻塞態或就緒態(後面將講述)。操做系統能夠把其餘進程設置爲運行態,把其餘進程的程序計數器和進程上下文數據加載處處理器寄存器中,這樣其餘進程就能夠開始執行了。網絡

 
圖3.1 簡化的進程控制塊

所以,進程是由程序代碼和相關數據還有進程控制塊組成。對於一個單處理器計算機,在任什麼時候間都最多隻有一個進程在執行,正在運行的這個進程的狀態爲運行態。數據結構

3.2 進程狀態

正如前面所提到的,對一個被執行的程序,操做系統會爲該程序建立一個進程或任務。併發

  • 從處理器的角度看,它在指令序列中按某種順序執行指令,這個順序根據程序計數器寄存器中不斷變化的值來指示,程序計數器可能指向不一樣進程中不一樣部分的程序代碼;
  • 從程序自身的角度看,它的執行涉及程序中的一系列指令。能夠經過列出爲該進程執行的指令序列來描述單個進程的行爲,這樣的序列稱作進程的軌跡。能夠經過給出各個進程的軌跡是如何被交替的來描述處理器的行爲。

舉例,圖3.2 給出了三個進程在內存中的佈局,爲簡化討論,假設沒有使用虛擬內存,所以全部三個進程都由徹底載入內存中的程序表示,此外,有一個小的分派器一1使處理器從一個進程切換到另外一個進程。圖3.3 給出了這三個進程在執行過程早期的軌跡,給出了進程A 和C 中最初執行的12 條指令,進程B 執行4 條指令,假設第4 條指令調用了進程必須等待的I/O 操做。編輯器

 
圖3.2 在指令週期13 時的執
行快照(如圖3.4 所示)

如今從處理器的角度看這些軌跡。圖3.4 給出了最初的52個指令週期中交替的軌跡(爲方便起見,指令週期都給出了編號)。在圖中,陰影部分表明由分配器執行的代碼。在每一個實例中由分派器執行的指令順序是相同的,由於是分派器的同一個功能在執行。假設操做系統僅容許一個進程最多連續執行6 個指令週期,在此以後將被中斷,這避免了任何一個進程獨佔處理器時間。如圖3.4 所示,進程A 最初的6 條指令被執行,接下來是一個超時並執行分派器的某些代碼,在控制轉移給進程B 以前分派器執行了6 條指令二2。在進程B 的4 條指令被執行後,進程B 請求一個它必須等待的I/O 動做,所以,處理器中止執行進程B,並經過分派器轉移到進程C。在超時後,處理器返回進程A,當此次處理超時時,進程B 仍然等待那個I/O 操做的完成,所以分派器再次轉移到進程C。模塊化

 
(點擊查看大圖)圖3.3 圖3.2 中進程的軌跡
 
(點擊查看大圖)圖3.4 圖3.2 中進程的組合軌跡

3.2.1 兩狀態進程模型

操做系統的基本職責是控制進程的執行,這包括肯定交替執行的方式和給進程分配資源。在設計控制進程的程序時,第一步就是描述進程所表現出的行爲。

任什麼時候刻,一個進程能夠處於如下兩種狀態之一:運行態或未運行態,如圖3.5a 所示。當操做系統建立一個新進程時,它將該進程以未運行態加入到系統中,操做系統知道這個進程是存在的,並正在等待執行機會。當前正在運行的進程不時地被中斷,操做系統中的分派器部分將選擇一個新進程運行。前一個進程從運行態轉換到未運行態,另一個進程轉換到運行態。

從這個簡單的模型能夠意識到操做系統的一些設計元素。必須用某種方式來表示每一個進程,使得操做系統可以跟蹤它,也就是說,必須有一些與進程相關的信息,包括進程在內存中的當前狀態和位置,即進程控制塊。未運行的進程必須保持在某種類型的隊列中,並等待它們的執行時機。圖3.5b 給出了一個結構,結構中有一個隊列,隊列中的每一項都指向某個特定進程的指針,或隊列能夠由數據塊構成的鏈表組成,每一個數據塊表示一個進程。

能夠用該排隊圖描述分派器的行爲。被中斷的進程轉移到等待進程隊列中,或者,若是進程已經結束或取消,則被銷燬(離開系統)。在任何一種狀況下,分派器均從隊列中選擇一個進程來執行。

 
圖3.5 兩狀態進程模型

3.2.2 進程的建立和終止

在對簡單的兩狀態模型進行改進以前,討論一下進程的建立和終止。不管使用哪一種進程行爲模型,進程的生存期都圍繞着進程的建立和終止。

進程的建立

當一個新進程添加到那些正在被管理的進程集合中去時,操做系統須要創建用於管理該進程的數據結構(見3.3 節),並在內存中給它分配地址空間。將在3.3 節中講述這些數據結構,這些行爲構成了一個新進程的建立過程。

一般有4 個事件會致使建立一個進程,如表。

  • 在批處理環境中,響應做業提交時會建立進程;
  • 在交互環境中,當一個新用戶試圖登陸時會建立進程。

不論在哪一種狀況下,操做系統都負責新進程的建立;操做系統也可能會表明應用程序建立進程,eg:若是用戶請求打印一個文件,則操做系統能夠建立一個管理打印的進程,進而使請求進程能夠繼續執行,與完成打印任務的時間無關。

表3.1 致使進程建立的緣由

 

傳統地,操做系統建立進程的方式對用戶和應用程序都是透明的。但容許一個進程引起另外一個進程的建立將是頗有用的。例如,一個應用程序進程能夠產生另外一個進程,以接收應用程序產生的數據,並將數據組織成適合之後分析的格式。新進程與應用程序並行地運行,並當獲得新的數據時被激活。這個方案對構造應用程序是很是有用的,例如,服務器進程(如打印服務器、文件服務器)能夠爲它處理的每一個請求產生一個新進程。當操做系統爲另外一個進程的顯式請求建立一個進程時,這個動做稱爲進程派生

當一個進程派生另外一個進程時,前一個稱作父進程,被派生的進程稱作子進程。在典型的狀況下,相關進程須要相互之間的通訊和合做。相關主題將在第5 章講述。

進程終止

表3.2 歸納了進程終止的典型緣由。任何一個計算機系統都必須爲進程提供表示其完成的方法,批處理做業中應該包含一個Halt 指令或用於終止的操做系統顯式服務調用來終止。

  • Halt 指令將產生一箇中斷,警告操做系統一個進程已經完成。
  • 對交互式應用程序,用戶的行爲將指出什麼時候進程完成,例如,在分時系統中,當用戶退出系統或關閉本身的終端時,該用戶的進程將被終止。在我的計算機或工做站中,用戶能夠結束一個應用程序(如字處理或電子表格)。全部這些行爲最終致使發送給操做系統的一個服務請求,以終止發出請求的進程。
  • 此外,不少錯誤和故障條件會致使進程終止。表3.2 列出了一些最多見的識別條件。
  • 最後,在有些操做系統中,進程能夠被建立它的進程終止,或當父進程終止時而終止。

表3.2 致使進程終止的緣由

 

3.2.3 五狀態模型

若是全部進程都作好了執行準備,則圖3.5b 所給出的排隊原則是有效的。隊列是「先進先出」的表,對於可運行的進程處理器以一種輪轉方式操做(依次給隊列中的每一個進程必定的執行時間,而後進程返回隊列,阻塞狀況除外)。但即便對前面描述的簡單例子,這個實現都是不合適的:存在着一些處於非運行狀態但已經就緒等待執行的進程,而同時存在另外的一些處於阻塞狀態等待I/O 操做結束的進程。所以,若是使用單個隊列,分派器不能只考慮選擇隊列中最老的進程,相反,它應該掃描這個列表,查找那些未被阻塞且在隊列中時間最長的進程

解決這種狀況的一種比較天然的方法是將非運行狀態分紅兩個狀態:就緒(ready)和阻塞(blocked),以下圖。新圖中的5 個狀態以下:

 
圖3.6 五狀態進程模型
  • 運行態:該進程正在執行。在本章中,假設計算機只有一個處理器,所以一次最多隻有一個進程處於這個狀態。
  • 就緒態:進程作好了準備,只要有機會就開始執行。
  • 阻塞/等待態:進程在某些事件發生前不能執行,如I/O 操做完成。
  • 新建態:剛剛建立的進程,操做系統尚未把它加入到可執行進程組中。一般是進程控制塊已經建立但尚未加載到內存中的新進程。
  • 退出態:操做系統從可執行進程組中釋放出的進程,或者是由於它自身中止了,或者是由於某種緣由被取消。

新建狀態對應於剛剛定義的進程。例如,若是一位新用戶試圖登陸到分時系統中,或者一個新的批做業被提交執行,那麼操做系統能夠分兩步定義新進程。

  • 首先,操做系統執行一些必需的輔助工做,將標識符關聯到進程,分配和建立管理進程所須要的全部表。此時,進程處於新建狀態,這意味着操做系統已經執行了建立進程的必需動做,但尚未執行進程。例如,操做系統可能基於性能或內存侷限性的緣由,限制系統中的進程數量。當進程處於新建態時,操做系統所須要的關於該進程的信息保存在內存中的進程表中,但進程自身還未進入內存,就是即將執行的程序代碼不在內存中,也沒有爲與這個程序相關的數據分配空間。當進程處於新建態時,程序保留在外存中,一般是磁盤中。

相似地,進程退出系統也分爲兩步。

  • 首先,當進程到達一個天然結束點時,因爲出現不可恢復的錯誤而取消時,或當具備相應權限的另外一個進程取消該進程時,進程被終止;終止使進程轉換到退出態,此時,進程再也不被執行了,與做業相關的表和其餘信息臨時被操做系統保留起來,這給輔助程序或支持程序提供了提取所需信息的時間。一個實用程序爲了分析性能和利用率,可能須要提取進程的歷史信息,一旦這些程序都提取了所須要的信息,操做系統就再也不須要保留任何與該進程相關的數據,該進程將從系統中刪除。

圖3.6 顯示了致使進程狀態轉換的事件類型。可能的轉換以下:

  • 空→新建:建立執行一個程序的新進程。這個事件在表3.1 中所列出的緣由下都會發生。
  • 新建→就緒:操做系統準備好再接納一個進程時,把一個進程重新建態轉換到就緒態。大多數系統基於現有的進程數或分配給現有進程的虛擬內存數量設置一些限制,以確保不會由於活躍進程的數量過多而致使系統的性能降低。
  • 就緒→運行:須要選擇一個新進程運行時,操做系統選擇一個處於就緒態的進程,這是調度器或分派器的工做。進程的選擇問題將在第四部分探討。
  • 運行→退出:若是當前正在運行的進程表示本身已經完成或取消,則它將被操做系統終止,見表3.2。
  • 運行→就緒:這類轉換最多見的緣由是,正在運行的進程到達了「容許不中斷執行」的最大時間段;實際上全部多道程序操做系統都實行了這類時間限定。這類轉換還有不少其餘緣由,例如操做系統給不一樣的進程分配不一樣的優先級,但這不是在全部的操做系統中都實現了的。假設,進程A 在一個給定的優先級運行,且具備更高優先級的進程B 正處於阻塞態。若是操做系統知道進程B 等待的事件已經發生了,則將B 轉換到就緒態,而後由於優先級的緣由中斷進程A 的執行,將處理器分派給進程B,咱們說操做系統搶佔了進程A。最後一種狀況是,進程自願釋放對處理器的控制,例如一個週期性地進行記帳和維護的後臺進程。
  • 運行→阻塞:若是進程請求它必須等待的某些事件,則進入阻塞態。對操做系統的請求一般以系統服務調用的形式發出,也就是說,正在運行的程序請求調用操做系統中一部分代碼所發生的過程。例如,進程可能請求操做系統的一個服務,但操做系統沒法當即予以服務,它也可能請求了一個沒法當即獲得的資源,如文件或虛擬內存中的共享區域;或者也可能須要進行某種初始化的工做,如I/O 操做所遇到的狀況,而且只有在該初始化動做完成後才能繼續執行。當進程互相通訊,一個進程等待另外一個進程提供輸入時,或者等待來自另外一個進程的信息時,均可能被阻塞。
  • 阻塞→就緒:當所等待的事件發生時,處於阻塞態的進程轉換到就緒態。
  • 就緒→退出:爲了清楚起見,狀態圖中沒有表示這種轉換。在某些系統中,父進程能夠在任什麼時候刻終止一個子進程。若是一個父進程終止,與該父進程相關的全部子進程都將被終止。
  • 阻塞→退出:前面一項提供了註釋。

再回到前面的簡單例子,圖3.7 顯示了每一個進程在狀態間的轉換,圖3.8a 給出了可能實現的排隊規則,有兩個隊列:就緒隊列和阻塞隊列。進入系統的每一個進程被放置在就緒隊列中,當操做系統選擇另外一個進程運行時,將從就緒隊列中選擇。對於沒有優先級的方案,這能夠是一個簡單的先進先出隊列。當一個正在運行的進程被移出處理器時,它根據狀況或者被終止,或者被放置在就緒或阻塞隊列中。最後,當一個事件發生時,全部位於阻塞隊列中等待這個事件的進程都被轉換到就緒隊列中。

 
圖3.7 圖3.4 中的進程狀態

後一種方案意味着當一個事件發生時,操做系統必須掃描整個阻塞隊列,搜索那些等待該事件的進程。在大型操做系統中,隊列中可能有幾百甚至幾千個進程,所以,擁有多個隊列將會頗有效,一個事件能夠對應一個隊列。那麼,當事件發生時,相應隊列中的全部進程都轉換到就緒態(見圖3.8b)。

 
(點擊查看大圖)圖3.8 圖3.6 的排隊模型

最後還有一種改進是,若是按照優先級方案分派進程,維護多個就緒隊列(每一個優先級一個隊列)將會帶來不少的便利。操做系統能夠很容易地肯定哪一個就緒進程具備最高的優先級且等待時間最長。

3.2.4 被掛起的進程

交換的須要

前面描述的三個基本狀態(就緒態、運行態和阻塞態)提供了一種爲進程行爲創建模型的系統方法,但能夠證實往模型中增長其餘狀態也是合理的。爲了說明加入新狀態的好處,考慮一個沒有使用虛擬內存的系統,每一個被執行的進程必須徹底載入內存,所以,圖3.8b 中,全部隊列中的全部進程必須駐留在內存中。

全部這些設計機制的緣由都是因爲I/O 活動比計算速度慢不少,所以在單道程序系統中的處理器在大多數時候是空閒的。可是圖3.8b 的方案並無徹底解決這個問題。在這種狀況下,內存保存有多個進程,當一個進程正在等待時,處理器能夠轉移到另外一個進程,可是處理器比I/O要快得多,以致於內存中全部的進程都在等待I/O 的狀況很常見。所以,即便是多道程序設計,大多數時候處理器仍然可能處於空閒狀態。

一種解決方法是內存能夠被擴充以適應更多的進程,可是這種方法有兩個缺陷。

  • 首先是內存的價格問題,當內存大小增長到兆位及千兆位時,價格也會隨之增長;
  • 再者,程序對內存空間需求的增加速度比內存價格降低的速度快。所以,更大的內存每每致使更大的進程,而不是更多的進程。

另外一種解決方案是交換,包括把內存中某個進程的一部分或所有移到磁盤中。當內存中沒有處於就緒狀態的進程時,操做系統就把被阻塞的進程換出到磁盤中的「掛起隊列」。操做系統在此以後取出掛起隊列中的另外一個進程,或者接受一個新進程的請求,將其歸入內存運行。進程行爲模型(見圖3.9a)中增長另外一個狀態:掛起態。

「交換」是一個I/O 操做,於是也可能使問題更加惡化。可是因爲磁盤I/O 通常是系統中最快的I/O(相對於磁帶或打印機I/O),因此交換一般會提升性能。

當操做系統已經執行了一個換出操做,它能夠有兩種將一個進程取到內存中的選擇:

  • 能夠接納一個新近建立的進程;
  • 或調入一個之前被掛起的進程。

一般比較傾向於調入一個之前被掛起的進程,給它提供服務,而不是增長系統中的負載總數。

但全部已經掛起的進程在掛起時都處於阻塞態。顯然,這時把被阻塞的進程取回內存沒有任何意義,由於它仍然沒有準備好執行。可是,掛起狀態中的每一個進程最初是阻塞在一個特定的事件上,當這個事件發生時,進程就再也不阻塞,能夠繼續執行。所以,須要從新考慮設計方式。有兩個獨立的概念:進程是否在等待一個事件(阻塞與否)以及進程是否已經被換出內存(掛起與否)。爲適應這種2×2 的組合,須要4 個狀態:

  • 就緒態:進程在內存中並能夠執行。
  • 阻塞態:進程在內存中並等待一個事件。
  • 阻塞/掛起態:進程在外存中並等待一個事件。
  • 就緒/掛起態:進程在外存中,可是隻要被載入內存就能夠執行。
 
圖3.9 有掛起態的進程狀態轉換圖

在查看包含兩個新掛起狀態的狀態轉換圖以前,必須提到另外一點。到如今爲止的論述都假設沒有使用虛擬內存,進程或者都在內存中,或者都在內存以外。在虛擬內存方案中,可能會執行到只有一部份內容在內存中的進程,若是訪問的進程地址不在內存中,則進程的相應部分能夠被調入內存。虛擬內存的使用看上去會消除顯式交換的須要,這是由於經過處理器中的存儲管理硬件,任何指望的進程中的任何指望的地址均可以移入或移出內存。可是,正如在第8 章中將會看到的,若是有足夠多的活動進程,而且全部進程都有一部分在內存中,則有可能致使虛擬內存系統崩潰。所以,即便在虛擬存儲系統中,操做系統也須要不時地根據執行狀況顯式地、徹底地換出進程。

如今來看圖3.9b 中咱們已開發的狀態轉換模型(圖中的虛線表示可能但並非必需的轉換)。比較重要的新的轉換以下:

  • 阻塞→阻塞/掛起:若是沒有就緒進程,則至少一個阻塞進程被換出,爲另外一個沒有阻塞的進程讓出空間。若是操做系統肯定當前正在運行的進程,或就緒進程爲了維護基本的性能要求而須要更多的內存空間,那麼,即便有可用的就緒態進程也可能出現這種轉換。
  • 阻塞/掛起→就緒/掛起:若是等待的事件發生了,則處於阻塞/掛起狀態的進程能夠轉換到就緒/掛起狀態。注意,這要求操做系統必須可以獲得掛起進程的狀態信息。
  • 就緒/掛起→就緒:若是內存中沒有就緒態進程,操做系統須要調入一個進程繼續執行。此外,當處於就緒/掛起態的進程比處於就緒態的任何進程的優先級都要高時,也能夠進行這種轉換。這種狀況的產生是因爲操做系統設計者規定調入高優先級的進程比減小交換量更重要。
  • 就緒→就緒/掛起:一般,操做系統更傾向於掛起阻塞態進程而不是就緒態進程,由於就緒態進程能夠當即執行,而阻塞態進程佔用了內存空間但不能執行。但若是釋放內存以獲得足夠空間的惟一方法是掛起一個就緒態進程,那麼這種轉換也是必需的。而且,若是操做系統確信高優先級的阻塞態進程很快將會就緒,那麼它可能選擇掛起一個低優先級的就緒態進程,而不是一個高優先級的阻塞態進程。

還須要考慮的幾種其餘轉換有:

  • 新建→就緒/掛起以及新建→就緒:當建立一個新進程時,該進程或者加入到就緒隊列,或者加入到就緒/掛起隊列中。不論哪一種狀況,操做系統都必須創建一些表以管理進程,併爲進程分配地址空間。操做系統可能更傾向於在初期執行這些輔助工做,這使得它能夠維護大量的未阻塞的進程。經過這個策略,內存中常常會沒有足夠的空間分配給新進程,所以使用了(新建→就緒/掛起)轉換。另外一方面,咱們能夠證實建立進程的適時(just-in-time)原理,即儘量推遲建立進程以減小操做系統的開銷,並在系統被阻塞態進程阻塞時容許操做系統執行進程建立任務。
  • 阻塞/掛起→阻塞:這種轉換在設計中比較少見,若是一個進程沒有準備好執行,而且不在內存中,調入它又有什麼意義?可是考慮到下面的狀況:一個進程終止,釋放了一些內存空間,阻塞/掛起隊列中有一個進程比就緒/掛起隊列中的任何進程的優先級都要高,而且操做系統有理由相信阻塞進程的事件很快就會發生,這時,把阻塞進程而不是就緒進程調入內存是合理的。
  • 運行→就緒/掛起:一般當分配給一個運行進程的時間期滿時,它將轉換到就緒態。可是,若是因爲位於阻塞/掛起隊列的具備較高優先級的進程變得再也不被阻塞,操做系統搶佔這個進程,也能夠直接把這個運行進程轉換到就緒/掛起隊形中,並釋放一些內存空間。
  • 各類狀態→退出:在典型狀況下,一個進程在運行時終止,或者是由於它已經完成,或者是由於出現了一些錯誤條件。可是,在某些操做系統中,一個進程能夠被建立它的進程終止,或當父進程終止時終止。若是容許這樣,則進程在任何狀態時均可以轉換到退出態。

掛起的其餘用途

到目前爲止,掛起進程的概念與不在內存中的進程概念是等價的一個不在內存中的進程,不論它是否在等待一個事件,都不能當即執行。

咱們能夠總結一下掛起進程的概念。首先,按照如下特色定義掛起進程:

  1. 進程不能當即執行。
  2. 進程多是或不是正在等待一個事件。若是是,阻塞條件不依賴於掛起條件,阻塞事件的發生不會使進程當即被執行。
  3. 爲阻止進程執行,能夠經過代理把這個進程置於掛起狀態,代理能夠是進程本身,也能夠是父進程或操做系統。
  4. 除非代理顯式地命令系統進行狀態轉換,不然進程沒法從這個狀態中轉移。

表3.3 列出了進程的一些掛起緣由。

  • 提供更多的內存空間,這樣能夠調入一個就緒/掛起態進程或增長分配給其餘就緒態進程的內存;
  • 操做系統由於其餘動機而掛起一個進程,例如,記帳或跟蹤進程可能用於監視系統的活動,可使用進程記錄各類資源(處理器、內存、通道)的使用狀況以及系統中用戶進程的進行速度。在操做員控制下的操做系統能夠不時地打開或關閉這個進程。
  • 若是操做系統發現或懷疑有問題,它能夠掛起進程。死鎖就是一個例子,將在第6 章講述。
  • 另外一個例子是,若是在進程測試時檢測到通訊線路中的問題,操做員讓操做系統掛起使用該線路的進程。

另一些緣由關係到交互用戶的行爲。例如,若是用戶懷疑程序中有缺陷,他(她)能夠掛起執行程序並進行調試,檢查並修改程序或數據,而後恢復執行;或者可能有一個收集記錄或記帳的後臺程序,用戶可能但願可以打開或關閉這個程序。

表3.3 致使進程掛起的緣由

 

時機的選擇也會致使一個交換決策。例如,若是一個進程週期性地被激活,但大多數時間是空閒的,則在它在兩次使用之間應該被換出。監視使用狀況或用戶活動的程序就是一個例子。

最後,父進程可能會但願掛起一個後代進程。例如,進程A 能夠生成進程B,以執行文件讀操做;隨後,進程B 在讀文件的過程當中遇到錯誤,並報告給進程A;進程A 掛起進程B,調查錯誤的緣由。

在全部這些狀況中,掛起進程的活動都是由最初請求掛起的代理請求的。

3.3 進程描述

操做系統控制計算機系統內部的事件,它爲處理器執行進程而進行調度和分派,給進程分配資源,並響應用戶程序的基本服務請求。所以,咱們能夠把操做系統看作是管理系統資源的實體。

這個概念如圖3.10 所示。在多道程序設計環境中,在虛擬內存中有許多已經建立了的進程,每一個進程在執行期間,須要訪問某些系統資源,包括處理器、I/O 設備和內存。在圖中,進程P1 正在運行,該進程至少有一部分在內存中,而且還控制着兩個I/O 設備;進程P2 也在內存中,但因爲正在等待分配給P1 的I/O 設備而被阻塞;進程Pn 已經被換出,所以是掛起的。

之後幾章中將探討操做系統表明進程管理這些資源的細節。這裏關心的是一些最基本的問題:操做系統爲了控制進程和管理資源須要哪些信息?

 
圖3.10 進程和資源(某一時刻的資源分配)

3.3.1 操做系統的控制結構

操做系統爲了管理進程和資源,必須掌握關於每一個進程和資源當前狀態的信息。廣泛使用的方法是:操做系統構造並維護它所管理的每一個實體的信息表。如圖3.11,操做系統維護着4 種不一樣類型的表:內存、I/O、文件和進程

 
圖3.11 操做系統控制表的通用結構

1、內存表用於跟蹤內(實)存和外存(虛擬內存)。內存的某些部分爲操做系統而保留,剩餘部分是進程可使用的,保存在外存中的進程使用某種類型的虛擬內存或簡單的交換機制。內存表必須包括如下信息:

  • 分配給進程的內存。
  • 分配給進程的外存。
  • 內存塊或虛擬內存塊的任何保護屬性,如哪些進程能夠訪問某些共享內存區域。
  • 管理虛擬內存所須要的任何信息。

第三部分將詳細講述用於內存管理的信息結構。

2、操做系統使用I/O 表管理計算機系統中的I/O 設備和通道。在任何給定的時刻,一個I/O 設備或者是可用的,或者已分配給某個特定的進程,若是正在進行I/O 操做,則操做系統須要知道I/O 操做的狀態和做爲I/O 傳送的源和目標的內存單元。在第11 章將詳細講述I/O 管理。

3、操做系統維護着文件表,這些表提供關於文件是否存在、文件在外存中的位置、當前狀態和其餘屬性的信息。大部分信息(不是所有信息)可能由文件管理系統維護和使用。在這種狀況下,操做系統只有一點或者沒有關於文件的信息;在其餘操做系統中,不少文件管理的細節由操做系統本身管理。這方面的內容將在第12 章講述。

4、最後,操做系統爲了管理進程必須維護進程表。須要先明確兩點:首先,儘管圖3.11 給出了4 種不一樣的表,可是這些表必須以某種方式連接起來或交叉引用。內存、I/O 和文件是表明進程而被管理的,所以進程表中必須有對這些資源的直接或間接引用。文件表中的文件能夠經過I/O 設備訪問,有時它們也位於內存中或虛擬內存中。這些表自身必須能夠被操做系統訪問到,所以它們受制於內存管理。

其次,操做系統最初如何知道建立表?顯然,操做系統必須有基本環境的一些信息,若有多少內存空間、I/O 設備是什麼以及它們的標識符是什麼等。這是一個配置問題,也就是說,當操做系統初始化後,它必須可使用定義基本環境的某些配置數據,這些數據必須在操做系統以外,經過人的幫助或一些自動配置軟件而產生。

3.3.2 進程控制結構

操做系統在管理和控制進程時,首先必須知道進程的位置以及在管理時所必需的進程屬性(如進程ID、進程狀態)。

進程位置

進程的物理表示是什麼?

  • 進程最少必須包括一個或一組被執行的程序,與這些程序相關聯的是局部變量、全局變量和任何已定義常量的數據單元。所以,一個進程至少包括足夠的內存空間,以保存該進程的程序和數據;
  • 此外,程序的執行一般涉及用於跟蹤過程調用和過程間參數傳遞的(見附錄1B)。
  • 最後,與每一個進程相關聯的還有操做系統用於控制進程的許多屬性,一般,屬性的集合稱作進程控制塊。

程序、數據、棧和屬性的集合稱作進程映像(process image)(見表3.4進程映像中的典型元素)。

 

進程映像的位置依賴於使用的內存管理方案。
最簡單的狀況,進程映像保存在鄰近的或連續的存儲塊中。該存儲塊位於外存(一般是磁盤)中。若是操做系統要管理進程,其進程映像至少有一部分必須位於內存中,爲執行該進程,整個進程映像必須載入內存中或至少載入虛擬內存中。所以,操做系統須要知道每一個進程在磁盤中的位置,而且對於內存中的每一個進程,須要知道其在內存中的位置。來看一下第2 章中CTSS 操做系統關於這個方案的一個稍微複雜些的變體。在CTSS 中,當進程被換出時,部分進程映像可能保留在內存中。所以,操做系統必須跟蹤每一個進程映像的哪一部分仍然在內存中。

現代操做系統假定分頁硬件容許用不連續的物理內存來支持部分常駐內存的進程。在任何給定的時刻,進程映像的一部分能夠在內存中,剩餘部分能夠在外存中。所以,操做系統維護的進程表必須代表每一個進程映像中每頁的位置。

圖3.11 描繪了位置信息的結構。有一個主進程表,每一個進程在表中都有一個表項,每一項至少包含一個指向進程映像的指針。若是進程映像包括多個塊,則這個信息直接包含在主進程表中,或能夠經過交叉引用內存表中的項獲得。固然,這個描述是通常性描述,特定的操做系統將按本身的方式組織位置信息。

進程屬性

每一個進程的大量信息該信息能夠保留在進程控制塊中。不一樣的系統以不一樣的方式組織該信息。表3.5( 進程控制塊中的典型元素) 列出了每一個進程信息的簡單分類。

能夠把進程控制塊信息分紅三類:

  • 進程標識信息
  • 處理器狀態信息
  • 進程控制信息
 
 

1、每一個進程都分配了一個惟一的數字標識符。進程標識符能夠簡單地表示爲主進程表(圖3.11 所示)中的一個索引;不然,必須有一個映射,使得操做系統能夠根據進程標識符定位相應的表。操做系統控制的許多其餘表可使用進程標識符交叉引用進程表。例如,內存表能夠組織起來以便提供一個關於內存的映射,指明每一個區域分配給了哪一個進程。I/O 表和文件表中也會有相似的引用。當進程相互之間進行通訊時,進程標識符可用於通知操做系統某一特定通訊的目標;當容許進程建立其餘進程時,標識符可用於指明每一個進程的父進程和後代進程。

除了進程標識符,還給進程分配了一個用戶標識符,用於標明擁有該進程的用戶。

2、處理器狀態信息包括處理器寄存器的內容。當一個進程正在運行時,其信息固然在寄存器中。當進程被中斷時,全部的寄存器信息必須保存起來,使得進程恢復執行時這些信息均可以被恢復。所涉及的寄存器的種類和數目取決於處理器的設計。在典型狀況下,寄存器組包括用戶可見寄存器、控制和狀態寄存器和棧指針,這些在第1 章中都曾介紹過。

處理器都包括一個或一組一般稱作程序狀態字( PSW)的寄存器,它包含狀態信息。PSW 一般包含條件碼和其餘狀態信息。Pentium處理器中的處理器狀態字就是一個很好的例子,它稱作EFLAGS 寄存器(如圖3.12 和表3.6 所示),可被運行在Pentium 處理器上的任何操做系統(包括UNIX 和Windows)使用。

3、進程控制信息是操做系統控制和協調各類活動進程所須要的額外信息。表3.5 代表了這類信息的範圍,隨後章節將進一步詳細分析。

圖3.13 給出了虛擬內存中進程映像的結構。每一個進程映像包括一個進程控制塊、用戶棧、進程的專用地址空間以及與別的進程共享的任何其餘地址空間。在這個圖中,每一個進程映像表現爲一段地址相鄰的區域。在實際的實現中可能不是這種狀況,這取決於內存管理方案和操做系統組織控制結構的方法。

 
圖3.12 PentiumⅡEFLAGS 寄存器

表3.6 Pentium EFLAGS 寄存器位

 

正如表3.5 中所指出的,進程控制塊還可能包含構造信息,包括將進程控制塊連接起來的指針。所以,前一節中所描述的隊列能夠由進程控制塊的鏈表實現,例如,圖3.8a 中的排隊結構能夠按圖3.14 中的方式實現。

進程控制塊的做用

每一個進程控制塊包含操做系統所須要的關於進程的全部信息。實際上,操做系統中的每一個模塊,包括那些涉及調度、資源分配、中斷處理、性能監控和分析的模塊,均可能讀取和修改它們。能夠說,資源控制塊集合定義了操做系統的狀態。

 
(點擊查看大圖)圖3.13 虛擬內存中的用戶進程

操做系統中的不少例程都須要訪問進程控制塊中,直接訪問這些表並不難,每一個進程都有一個惟一ID 號,可用做進程控制塊指針表的索引。困難的不是訪問而是保護,具體表現爲下面兩個問題:

  • 一個例程(如中斷處理程序)中有錯誤,可能會破壞進程控制塊,進而破壞了系統對受影響進程的管理能力。
  • 進程控制塊的結構或語義的設計變化可能會影響到操做系統中的許多模塊。

這些問題能夠經過要求操做系統中的全部例程都經過一個處理例程來專門處理,處理例程的任務僅僅是保護進程控制塊,它是讀寫這些塊的惟一的仲裁程序。使用這類進程,須要權衡性能問題和對系統軟件剩餘部分正確性的信任程度。

 

圖3.14 進程鏈表結構

3.4 進程控制

3.4.1 執行模式

首先需區分「與操做系統相關聯的」以及「與用戶程序相關聯」的處理器執行模式。
某些指令只能在特權態下運行,包括讀取或改變諸如程序狀態字之類控制寄存器的指令、原始I/O 指令和與內存管理相關的指令。另外,有部份內存區域僅在特權態下能夠被訪問到。

  • 非特權態常稱作用戶態,用戶程序一般在該模式下運行;
  • 特權態可稱作系統態、控制態或內核態,內核態指的是操做系統的內核,是操做系統中包含重要系統功能的部分。

表3.7 操做系統內核的典型功能

 

使用兩種模式的緣由:保護操做系統和重要的操做系統表(如進程控制塊)不受用戶程序的干涉。在內核態下,軟件具備對處理器以及全部指令、寄存器和內存的控制能力,這一級的控制對用戶程序不是必需的,且爲了安全起見也不是用戶程序可訪問的。

這樣產生了兩個問題:處理器如何知道它正在什麼模式下執行以及如何改變這一模式。
對第一個問題,程序狀態字中有一位表示執行模式,這一位應某些事件的要求而改變。在典型狀況下,當用戶調用一個操做系統服務或中斷觸發系統例程的執行時,執行模式被設置成內核態,當從系統服務返回到用戶進程時,執行模式被設置爲用戶態。例如64 位IA-64 體系結構的Intel Itanium 處理器,有一個處理器狀態寄存器(PSR),包含2 位的CPL(當前特權級別)域,級別0 是最高特權級別,級別3 是最低特權級別。大多數操做系統,如Linux,使用級別0 做爲內核態,使用另外一個級別做爲用戶態。當中斷髮生時,處理器清空大部分PSR 中的位,包括CPL域,這將自動把CPL 設置爲0。在中斷處理例程結束時,最後的一個指令是irt(中斷返回),這條指令使處理器恢復中斷程序的PSR 值,也就是恢復了程序的特權級別。當應用程序調用一個系統調用時,會發生相似的狀況。對於Itanium,應用程序使用系統調用是經過如下方式實現的:把系統調用標識符和參數放在一個預約義的區域,而後經過執行一個特殊的指令中斷用戶態程序的執行,並把控制權交給內核。

3.4.2 進程建立

討論了與進程相關的數據結構後,可簡單描述實際建立進程時的步驟。

一旦操做系統決定基於某種緣由(見表3.1)建立一個新進程,可按如下步驟進行:

  • 給新進程分配一個惟一的進程標識符。此時,在主進程表中增長一個新表項,表中的每一個新表項對應着一個進程。
  • 進程分配空間。這包括進程映像中的全部元素。操做系統須知道私有用戶地址空間(程序和數據)和用戶棧須要多少空間。能夠根據進程的類型使用默認值,也能夠在做業建立時根據用戶請求設置。若是一個進程是由另外一個進程生成的,則父進程能夠把所需的值做爲進程建立請求的一部分傳遞給操做系統。若是任何現有的地址空間被這個新進程共享,則必須創建正確的鏈接。最後,必須給進程控制塊分配空間。
  • 初始化進程控制塊。進程標識符部分;處理器狀態信息部分的大多數項目一般初始化成0,除了程序計數器(被置爲程序入口點)和系統棧指針(用來定義進程棧邊界);進程控制信息部分的初始化基於標準默認值和爲該進程所請求的屬性。例如,進程狀態在典型狀況下被初始化成就緒或就緒/掛起;除非顯式地請求更高的優先級,不然優先級的默認值爲最低優先級;除非顯式地請求或從父進程處繼承,不然進程最初不擁有任何資源(I/O 設備、文件)。
  • 設置正確的鏈接。例如,若是操做系統把每一個調度隊列都保存成鏈表,則新進程必須放置在就緒或就緒/掛起鏈表中。
  • 建立或擴充其餘數據結構。例如,操做系統可能爲每一個進程保存着一個記帳文件,可用於編制帳單和/或進行性能評估。

3.4.3 進程切換

表面看進程切換的功能是簡單的。某一時刻,一個正在運行的進程被中斷,操做系統指定另外一個進程爲運行態,並把控制權交給這個進程。

  • 什麼事件觸發進程的切換?
  • 模式切換與進程切換之間的區別。
  • 爲實現進程切換,操做系統須對它控制的各類數據結構作些什麼?

什麼時候切換進程

進程切換在操做系統從當前正在運行的進程中得到控制權的任什麼時候刻發生。表3.8 給出了可能把控制權交給操做系統的事件。

1、系統中斷。大多數操做系統區分兩種類型的系統中斷:

  • 中斷,與當前正在運行的進程無關的某種類型的外部事件相關,如完成一次I/O 操做;
  • 陷阱,與當前正在運行的進程所產生的錯誤或異常條件相關,如非法的文件訪問。

對於普通中斷,控制首先轉移給中斷處理器,它作一些基本的輔助工做,而後轉到與已經發生的特定類型的中斷相關的操做系統例程。參見如下例子:

  • 時鐘中斷:操做系統肯定當前正在運行的進程的執行時間是否已經超過了最大容許時間段(時間片,即進程在被中斷前能夠執行的最大時間段),若是超過了,進程必須切換到就緒態,調入另外一個進程。
  • I/O 中斷:操做系統肯定是否發生了I/O 活動。若是I/O 活動是一個或多個進程正在等待的事件,操做系統就把全部相應的阻塞態進程轉換到就緒態(阻塞/掛起態進程轉換到就緒/掛起態),操做系統必須決定是繼續執行當前處於運行態的進程,仍是讓具備高優先級的就緒態進程搶佔這個進程。
  • 內存失效:處理器訪問一個虛擬內存地址,且此地址單元不在內存中時,操做系統必須從外存中把包含這個引用的內存塊(頁或段)調入內存中。在發出調入內存塊的I/O 請求以後,操做系統可能會執行一個進程切換,以恢復另外一個進程的執行,發生內存失效的進程被置爲阻塞態,當想要的塊調入內存中時,該進程被置爲就緒態。

2、對於陷阱,操做系統肯定錯誤或異常條件是不是致命的。若是是,當前正在運行的進程被轉換到退出態,併發生進程切換;若是不是,操做系統的動做取決於錯誤的種類和操做系統的設計,其行爲能夠是試圖恢復或通知用戶,操做系統可能會進行一次進程切換或者繼續執行當前正在運行的進程。

3、操做系統可能被來自正在執行的程序的系統調用激活。例如,一個用戶進程正在運行,而且正在執行一條請求I/O 操做的指令,如打開文件,這個調用致使轉移到做爲操做系統代碼一部分的一個例程上執行。一般,使用系統調用會致使把用戶進程置爲阻塞態。

表3.8 進程執行的中斷機制

 

模式切換

中斷階段,處理器經過中斷信號檢查是否發生了任何中斷。若沒有未處理的中斷,處理器繼續取指令週期,即取當前進程中的下一條指令,若存在未處理的中斷,處理器須要作如下工做:

  • 把程序計數器置成中斷處理程序的開始地址
  • 從用戶態切換到內核態,使得中斷處理代碼能夠包含有特權的指令

處理器繼續取指階段,並取中斷處理程序的第一條指令,它將給中斷提供服務。此時,被中斷的進程上下文保存在被中斷程序的進程控制塊中

保存的上下文環境包括什麼?全部中斷處理可能改變的信息和恢復被中斷程序時所須要的信息。所以,須保存稱作處理器狀態信息的進程控制塊部分,這包括程序計數器、其餘處理器寄存器和棧信息。

還須要作些其餘工做嗎?取決於下一步會發生什麼。中斷處理程序一般執行與中斷相關的基本任務的小程序。例如,它重置表示出現中斷的標誌或指示器。可能給產生中斷的實體如I/O 模塊發送應答。它還作一些與產生中斷的事件結果相關的基本輔助工做。例如,若是中斷與I/O 事件有關,中斷處理程序將檢查錯誤條件;若是發生了錯誤,中斷處理程序給最初請求I/O操做的進程發一個信號。若是是時鐘中斷,處理程序將控制移交給分派器,當分配給當前正在運行進程的時間片用盡時,分派器將控制轉移給另外一個進程。

進程控制塊中的其餘信息如何處理?若是中斷以後是切換到另外一個應用程序,則須要作一些工做。可是,在大多數操做系統中,中斷的發生並非必須伴隨着進程切換的。多是中斷處理器執行以後,當前正在運行的進程繼續執行。在這種狀況下,所須要作的是當中斷髮生時保存處理器狀態信息,當控制返回給這個程序時恢復這些信息。在典型狀況下,保存和恢復功能由硬件實現。

進程狀態的變化

顯然,模式切換與進程切換是不一樣的。發生模式切換能夠不改變正處於運行態的進程狀態,這種狀況下,保存上下文環境和之後恢復上下文環境只須要不多的開銷。可是,若是當前正在運行的進程被轉換到另外一個狀態(就緒、阻塞等),則操做系統必須使其環境產生實質性的變化,完整的進程切換步驟以下:

  • 保存處理器上下文環境,包括程序計數器和其餘寄存器。
  • 更新當前處於運行態進程的進程控制塊,包括將進程的狀態改變到另外一狀態(就緒態、阻塞態、就緒/掛起態或退出態)。還必須更新其餘相關域,包括離開運行態的緣由和記帳信息。
  • 將進程的進程控制塊移到相應的隊列(就緒、在事件i 處阻塞、就緒/掛起)。
  • 選擇另外一個進程執行,這方面的內容將在本書的第四部分探討
  • 更新所選擇進程的進程控制塊,包括將進程的狀態變爲運行態。
  • 更新內存管理的數據結構,這取決於如何管理地址轉換,這方面的內容將在第三部分探討。
  • 恢復處理器在被選擇的進程最近一次切換出運行狀態時的上下文環境,這能夠經過載入程序計數器和其餘寄存器之前的值來實現。

所以,進程切換涉及狀態變化,於是比模式切換須要作更多的工做。

3.5 操做系統的執行

操做系統的兩個特殊事實:

  • 操做系統與普通的計算機軟件以一樣的方式運行,也就是說,它也是由處理器執行的一個程序。
  • 操做系統常常釋放控制權,而且依賴於處理器恢復控制權。

若操做系統僅僅是一組程序,那麼操做系統是一個進程嗎?若是是,如何控制它?這些有趣的問題列出了大量的設計方法,圖3.15 給出了在當代各類操做系統中使用的各類方法。

3.5.1 無進程的內核

老操做系統中,傳統和通用的方法是在全部的進程以外執行操做系統內核(見圖3.15a)。經過這種方法,在當前正運行的進程被中斷或產生一個系統調用時,該進程的模式上下文環境被保存起來,控制權轉交給內核。操做系統有本身的內存區域和系統棧,用於控制過程調用和返回。操做系統能夠執行任何預期的功能,並恢復被中斷進程的上下文,這將致使被中斷的用戶進程從新繼續執行。或者,操做系統能夠完成保存進程環境的功能,並繼續調度和分派另外一個進程,是否這樣作取決於中斷的緣由和當前的狀況。

不管哪一種狀況,其關鍵點是進程的概念僅僅適用於用戶程序,操做系統代碼做爲一個在特權模式下工做的獨立實體被執行。

3.5.2 在用戶進程中執行

在較小的機器的操做系統中,常見的方法是在用戶進程的上下文中執行幾乎全部操做系統軟件。其觀點是操做系統從根本上說是用戶調用的一組例程,在用戶進程環境中執行,用於實現各類功能,如圖3.15b 所示。在任什麼時候刻,操做系統管理着n 個進程映像,每一個映像不只包括圖3.13 中列出的區域,並且還包括內核程序的程序、數據和棧區域。

 
圖3.15 操做系統和用戶進程的關係

圖3.16 給出了這個策略下的一個典型的進程映像結構。當進程在內核態下時,獨立的內核棧用於管理調用/返回。操做系統代碼和數據位於共享地址空間中,被全部的用戶進程共享。

 
圖3.16 進程映像:操做
系統在用戶空間中執行

當發生一箇中斷、陷阱或系統調用時,處理器被置於內核態,控制權轉交給操做系統。爲了將控制從用戶程序轉交給操做系統,須要保存模式上下文環境並進行模式切換,而後切換到一個操做系統例程,但此時仍然是在當前用戶進程中繼續執行,所以,不須要執行進程切換,僅在同一個進程中進行模式切換。

若是操做系統完成其操做後,肯定須要繼續運行當前進程,則進行一次模式切換,在當前進程中恢復被中斷的程序。該方法的重要優勢之一是,一個用戶程序被中斷以使用某些操做系統例程,而後被恢復,全部這些不用以犧牲兩次進程切換爲代價。若是肯定須要發生進程切換而不是返回到先前執行的程序,則控制權被轉交給進程切換例程,這個例程可能在當前進程中執行,也可能不在當前進程中執行,這取決於系統的設計。在某些特殊的狀況下,如當前進程必須置於非運行態,而另外一個進程將指定爲正在運行的進程。爲方便起見,這樣一個轉換過程在邏輯上能夠看作是在全部進程以外的環境中被執行的。

在某種程度上,對操做系統的這種見解是很是值得注意的。在某些時候,一個進程能夠保存它的狀態信息,從就緒態進程中選擇另外一個進程,並把控制權釋放給這個進程。之因此說這是一種混雜的狀況,是由於在關鍵時候,在用戶進程中執行的代碼是共享的操做系統代碼而不是用戶代碼。基於用戶態和內核態的概念,即便操做系統例程在用戶進程環境中執行,用戶也不能篡改或干涉操做系統例程。這進一步說明進程和程序的概念是不一樣的,它們之間不是一對一的關係。在一個進程中,用戶程序和操做系統程序都有可能執行,而在不一樣用戶進程中執行的操做系統程序是相同的。

3.5.3 基於進程的操做系統

圖3.15c 中顯示的是另外一種選擇,即把操做系統做爲一組系統進程來實現。與其餘選擇同樣,做爲內核一部分的軟件在內核態下執行。不過在這種狀況下,主要的內核函數被組織成獨立的進程,一樣,還可能有一些在任何進程以外執行的進程切換代碼。

這種方法有幾個優勢。它利用程序設計原理,促使使用模塊化操做系統,而且模塊間具備最小的、簡明的接口。此外,一些非關鍵的操做系統函數可簡單地用獨立的進程實現,例如,很早就曾經提到過的用於記錄各類資源(處理器、內存、通道)的使用程度和系統中用戶進程的執行速度的監控程序。因爲這個程序沒有爲任何活動進程提供特定的服務,它只能被操做系統調用。做爲一個進程,這個函數能夠在指定的優先級上運行,而且在分派器的控制下與其餘進程交替執行。最後,把操做系統做爲一組進程實現,在多處理器或多機環境中都是十分有用的,這時一些操做系統服務能夠傳送到專用處理器中執行,以提升性能。

3.6 安全問題

操做系統對於每一個進程都關聯了一套權限。這些權限規定了進程能夠獲取哪些資源,包括內存區域、文件和特權系統指令等。典型的是,一個進程的運行表明着一個用戶擁有操做系統認證的權限。在配置的時候,一個系統或者是一個實用進程就被分配了權限。

在一個典型的系統中,最高級別的權限指的是管理員、超級用戶或根用戶的訪問權限。根用戶的訪問權限提供了對一個操做系統全部的功能和服務的訪問。一個有着根用戶訪問權限的進程能夠安全地控制一個系統,能夠增長或者改變程序和文件,對其餘進程進行監控,發送和接收網絡流量和改變權限。

設計任何操做系統的一個關鍵問題是阻止或者至少是探測一個用戶或者是一種惡意軟件(惡意程序)得到系統受權的權限的企圖,尤爲是從根用戶獲取。本節,咱們將簡短地總結關於這種安全問題的威脅和對策。在第七部分將對其作更加詳細的闡述。

3.6.1 系統訪問威脅

系統訪問威脅分爲兩大類:入侵者和惡意軟件。

入侵者

對於安全,一個最普通的威脅就是入侵者(另一個是病毒),一般是指黑客和解密高手。在早期的一項對入侵的重要研究中,Anderson [ANDE80] 定義了三種類型的入侵者:

冒充者:沒有受權的我的去使用計算機和經過穿透系統的訪問控制去使用一個合法用戶的帳號。

濫用職權者:一個合法的用戶訪問沒有受權的數據、程序或資源,或者用戶具備這種訪問的受權,可是濫用了他的權限。

祕密用戶:一個用戶得到了系統的管理控制,而後使用這種控制來逃避審計和訪問控制,或者廢止審查收集。

冒充者有可能就是外部人員;濫用職權者通常都是內部人員;祕密用戶多是外部人員也多是內部人員。

入侵者的攻擊有良性的也有嚴重的。在良性階段,許多人僅僅是想瀏覽互聯網並想知道在互聯網上到底有什麼。在嚴重階段,這些人嘗試着去讀權限數據,修改未受權的數據或者是破壞系統。

入侵者的目的是得到一個系統的訪問權限,或是增長一個系統的權限獲取的範圍。最初許多攻擊是利用了系統或軟件的漏洞,這些漏洞可讓用戶執行能夠開啓系統後門的代碼。當程序以必定的權限運行,入侵者能夠利用如緩衝溢出區攻擊來得到系統的訪問。將在7 章介紹緩衝區溢出攻擊。

此外,入侵者也能夠嘗試獲取那些已經被保護的信息。在一些狀況下,信息就是在表框裏面的用戶密碼。若是知道了一些用戶的密碼,那麼入侵者能夠登陸一個系統,而後運行合法用戶的全部權限。

惡意軟件

計算機系統最爲複雜的威脅可能就是利用計算機系統漏洞的程序。這些威脅被稱爲惡意軟件,或者是惡意程序。在這一部分,咱們將關注如編輯器、編譯器和內核級程序等應用程序以及通用程序的威脅。

惡意軟件分爲兩大類:一種須要宿主程序,一種則是獨立的。對於前者,也被稱爲寄生,其本質上是一些不能獨立於實際應用程序、通用程序或系統程序而存在的片斷,例如病毒、邏輯炸彈和後門。後者則是獨立並能夠被操做系統調度和運行的程序,例如蠕蟲和殭屍程序。

咱們也能夠對這些軟件威脅進行如下的區分:一種不能進行復制,而另一種則能夠。前者是經過觸發器激活的程序或者程序片斷,例如,邏輯炸彈、後門和殭屍程序。後者由一個程序片斷或者一個獨立的程序構成,當其運行後,可能產生一個或者多個它本身的副本,這些副本將在同一系統或其餘系統中被激活,例如病毒和蠕蟲。

比較而言,惡意軟件多是無害的,或者表現爲一個或多個有害的操做,這些有害的操做包括毀壞內存裏的文件和數據,經過繞開控制而得到權限訪問和爲入侵者提供一種繞開訪問控制的方法。

3.6.2 對抗措施

入侵檢測

RFC2828(網絡安全術語表)對入侵檢測的定義以下:入侵檢測是一種安全服務,經過監控和分析系統事件發現試圖經過未經受權的方法訪問系統資源的操做,並對這種操做提供實時或者準實時的警告。

入侵檢測系統(IDS)能夠分爲以下幾類:

基於宿主的IDS:對於可疑活動,監控單個宿主的特徵和發生在宿主上的事件。

基於網絡的IDS:監控特定的網絡段或者設備網絡流量,分析網絡、傳輸和應用協議來辨別可疑活動。

IDS 由三個部分組成:

感應器:感應器負責收集數據。感應器的輸入多是系統的任一部分,輸入可能包含了侵擾的證據。典型的感應器輸入包括網絡包、日誌文件和系統調用記錄。感應器收集這些信息,並把這些信息發送給分析器。

分析器:分析器從一個或多個感應器或者其餘分析器接受輸入數據。分析器負責肯定入侵是否發生。這部分的輸出代表了一個入侵已經發生。輸出可能包含了支持入侵發生的結論的證據。分析器可能提供對於入侵結果採起何種操做的指導。

用戶界面:IDS 的用戶界面可讓用戶查看系統的輸出和控制系統的行爲。在一些系統中,用戶界面能夠等同於負責人、控制器或者控制檯部分。

入侵檢測系統用來偵測人類入侵者行爲,以及惡意軟件的行爲。

認證

在許多計算機安全內容中,用戶認證是一個主要的構建模塊和最初防線。用戶認證是許多種訪問控制和用戶責任的主要部分。RFC2828 對用戶認證作了以下定義:

系統實體定義了驗證和確認的過程。認證過程包括如下兩步:

確認步驟:對於安全系統,提出了標識符。(應當心地分配標識符,對於訪問控制服務等其餘安全服務,認證定義是基本部分。)

驗證步驟:提出或產生認證信息,用來證明在實體與標識符之間的綁定。

例如,用戶Alice Toklas 擁有一個用戶標識符ABTOKLAS。標識符信息可能被存儲在Alice想要使用的任意一臺服務器或者計算機系統中,並且系統管理員和其餘用戶可能知道這些信息。一種典型的與用戶ID 相關聯的認證信息項就是密碼,密碼是用於保守祕密的(祕密僅僅被Alice和系統所知)。若是沒有人獲得或猜出Alice 的密碼,管理員能夠經過Alice 的用戶ID 和密碼的結合創建Alice 的訪問許可,並審覈Alice 的操做。因爲Alice 的ID 不是祕密,系統用戶能夠給她發送電子郵件,可是因爲她的密碼是保密的,因此沒有人能夠冒充成Alice。

本質上,識別是這樣一種方法:用戶向系統提供一個聲明的身份;用戶認證就是確認聲明的合法性的方法。

一共有4 種主要的認證用戶身份的方法,它們既能夠單獨使用,也能夠聯合使用:

我的知道的一些事物:例如包括密碼、我的身份號碼(PIN)或者是預先安排的一套問題的答案。

我的擁有的一些事物:例如包括電子通行卡、智能卡、物理鑰匙。這種類型的身份驗證稱爲令牌。

我的自身的事物(靜態生物識別技術):例如包括指紋、虹膜和人臉的識別。

我的要作的事物(動態生物識別技術):例如包括語音模式、筆跡特徵和輸入節奏的識別。

適當的實現和使用全部的這些方法,能夠提供可靠的用戶認證。可是每一個方法都有問題,使得對手可以猜想或盜取密碼。相似地,用戶可以僞造或盜取令牌。用戶可能忘記密碼或丟失令牌。並且,對於管理系統上的密碼、令牌信息和保護系統上的這些信息,還存在顯著的管理開銷。對於生物識別技術,也有各類各樣的問題,包括誤報和假否認、用戶接受程度、費用和便利與否。

訪問控制

訪問控制實現了一種安全策略:指定誰或何物(例如進程的狀況)可能有權使用特定的系統資源和在每一個場景下被容許的訪問類型。

訪問控制機制調節了用戶(或是表明用戶執行的進程)與系統資源之間的關係,系統資源包括應用程序、操做系統、防火牆、路由器、文件和數據庫。系統首先要對尋求訪問的用戶進行認證。一般,認證功能徹底決定了用戶是否被容許訪問系統。而後訪問控制功能決定了是否容許用戶的特定訪問要求。安全管理員維護着一個受權數據庫,對於容許用戶對何種資源採用什麼樣的訪問方式,受權數據庫作了詳細說明。訪問控制功能參考這個數據庫來決定是否准予訪問。審覈功能監控和記錄了用戶對於系統資源的訪問。

防火牆

對於保護本地系統或系統網絡免於基於網絡的安全威脅,防火牆是一種有效的手段,而且防火牆同時提供了通過廣域網和互聯網對外部網絡的訪問。傳統上,防火牆是一種專用計算機,是計算機與外部網絡的接口;防火牆內部創建了特殊的安全預防措施用以保護網絡中計算機上的敏感文件。其被用於服務外部網絡,尤爲是互聯網、鏈接和撥號線路。使用硬件或軟件來實現,而且與單一的工做站或者PC 鏈接的我的防火牆也很常見。

[BELL94]列舉了以下防火牆的設計目標:

1)從內部到外部的通訊必須經過防火牆,反之亦然。經過對除通過防火牆以外本地網絡的全部訪問都進行物理阻塞來達到目的。能夠對其進行各類各樣的配置,將在本章的後面部分進行闡述。

2)僅僅容許本地安全策略定義的受權通訊經過。使用的不一樣類型防火牆是經過不一樣類型的安全策略實現的。

3)防火牆自己對於滲透是免疫的。這意味着在一個安全的操做系統上使用強固系統。值得信賴的計算機系統適合用做防火牆,而且在管理應用中也被要求使用。

3.7 UNIX SVR4 進程管理

UNIX 系統V 使用了一種簡單可是功能強大的進程機制,且對用戶可見。UNIX 採用圖3.15b 中的模型,其中大部分操做系統在用戶進程環境中執行。UNIX 使用兩類進程,即系統進程和用戶進程。系統進程在內核態下運行,執行操做系統代碼以實現管理功能和內部處理,如內存空間的分配和進程交換;用戶進程在用戶態下運行以執行用戶程序和實用程序,在內核態下運行以執行屬於內核的指令。當產生異常(錯誤)或發生中斷或用戶進程發出系統調用時,用戶進程可進入內核態。

3.7.1 進程狀態

UNIX 操做系統中共有9 種進程狀態,如表3.9 所示。圖3.17(基於[BACH86]中的圖)是相應的狀態轉換圖,它與圖3.9b 相似,有兩個UNIX 睡眠狀態對應於圖3.9b 中的兩個阻塞狀態,其區別可簡單歸納以下:

UNIX 採用兩個運行態表示進程在用戶態下執行仍是在內核態下執行。

UNIX 區份內存中就緒態和被搶佔態這兩個狀態。從本質上看,它們是同一個狀態,如圖中它們之間的虛線所示,之因此區分這兩個狀態是爲了強調進入被搶佔狀態的方式。當一個進程正在內核態下運行時(系統調用、時鐘中斷或I/O 中斷的結果),內核已經完成了其任務並準備把控制權返回給用戶程序時,就可能會出現搶佔的時機。這時,內核可能決定搶佔當前進程,支持另外一個已經就緒並具備較高優先級的進程。在這種狀況下,當前進程轉換到被搶佔態,可是爲了分派處理,處於被搶佔態的進程和處於內存中就緒態的進程構成了一條隊列。

 
圖3.17 UNIX 進程狀態轉換圖

只有當進程準備從內核態移到用戶態時纔可能發生搶佔,進程在內核態下運行時是不會被搶佔的,這使得UNIX 不適用於實時處理。有關實時處理需求的討論請參見第10 章。

UNIX 中有兩個獨特的進程。進程0 是一個特殊的進程,是在系統啓動時建立的。實際上,這是預約義的一個數據結構,在啓動時刻被加載,是交換進程。此外,進程0 產生進程1,稱作初始進程,進程1 是系統中的全部其餘進程的祖先。當新的交互用戶登陸到系統時,由進程1爲該用戶建立一個用戶進程。隨後,用戶進程能夠建立子進程,從而構成一棵分支樹,所以,任何應用程序都是由一組相關進程組成的。

表3.9 UNIX 進程狀態

 

 

3.7.2 進程描述

UNIX 中的進程是一組至關複雜的數據結構,它給操做系統提供管理進程和分派進程所須要的全部信息。表3.10 歸納了進程映像中的元素,它們被組織成三部分:用戶上下文、寄存器上下文和系統級上下文。

表3.10 UNIX 進程映像

 

 

 

用戶級上下文包括用戶程序的基本成分,能夠由已編譯的目標文件直接產生。用戶程序被分紅正文和數據兩個區域,正文區是隻讀的,用於保存程序指令。當進程正在執行時,處理器使用用戶棧進行過程調用和返回以及參數傳遞。共享內存區是與其餘進程共享的數據區域,它只有一個物理副本,可是經過使用虛擬內存,對每一個共享進程來講,共享內存區看上去好像在它們各自的地址空間中同樣。當進程沒有運行時,處理器狀態信息保存在寄存器上下文中。

系統級上下文包含操做系統管理進程所須要的其他信息,它由靜態部分和動態部分組成,靜態部分的大小是固定的,貫穿於進程的生命週期;動態部分在進程的生命週期中大小可變。靜態部分的一個成分是進程表項,這其實是由操做系統維護的進程表的一部分,每一個進程對應於表中的一項。進程表項包含對內核來講老是能夠訪問到的進程控制信息。所以,在虛擬內存系統中,全部的進程表項都在內存中,表3.11 中列出了進程表項的內容。用戶區,即U 區,包含內核在進程的上下文環境中執行時所須要的額外的進程控制信息,當進程調入或調出內存時也會用到它。表3.12 給出了這個表的內容。

表3.11 UNIX 進程表項

 

 

 

(續)

 

 

 


表3.12 UNIX 的U 區

 

 

 

進程表項和U 區的區別反映出UNIX 內核老是在某些進程的上下文環境中執行,大多數時候,內核都在處理與該進程相關的部分,可是,某些時候,如當內核正在執行一個調度算法,準備分派另外一個進程時,它須要訪問其餘進程的相關信息。當給定進程不是當前進程時,能夠訪問進程控制表中的信息。

系統級上下文靜態部分的第三項是本進程區表,它由內存管理系統使用。最後,內核棧是系統級上下文環境的動態部分,當進程正在內核態下執行時須要使用這個棧,它包含當發生過程調用或中斷時必須保存和恢復的信息。

3.7.3 進程控制

UNIX 中的進程建立是經過內核系統調用fork()實現的。當一個進程產生一個fork 請求時,操做系統執行如下功能[BACH86]:

1)爲新進程在進程表中分配一個空項。

2)爲子進程賦一個惟一的進程標識符。

3)作一個父進程上下文的邏輯副本,不包括共享內存區。

4)增長父進程擁有的全部文件的計數器,以表示有一個另外的進程如今也擁有這些文件。

5)把子進程置爲就緒態。

6)向父進程返回子進程的進程號;對子進程返回零。

全部這些操做都在父進程的內核態下完成。爲當內核完成這些功能後能夠繼續下面三種操做之一,它們能夠認爲是分派器例程的一個部分:

在父進程中繼續執行。控制返回用戶態下父進程進行fork 調用處。

處理器控制權交給子進程。子進程開始執行代碼,執行點與父進程相同,也就是說在fork調用的返回處。

控制轉交給另外一個進程。父進程和子進程都置於就緒狀態。

很難想象這種建立進程的方法中父進程和子進程都執行相同的代碼。其區別在於:當從fork中返回時,測試返回參數,若是值爲零,則它是子進程,能夠轉移到相應的用戶程序中繼續執行;若是值不爲零,則它是父進程,繼續執行主程序。

3.8 小結

現代操做系統中最基本的構件是進程,操做系統的基本功能是建立、管理和終止進程。當進程處於活躍狀態時,操做系統必須設法使每一個進程都分配處處理器執行時間,並協調它們的活動、管理有衝突的請求、給進程分配系統資源。

爲執行進程管理功能,操做系統維護着對每一個進程的描述,或者稱爲進程映像,它包括執行進程的地址空間和一個進程控制塊。進程控制塊含有操做系統管理進程所須要的全部信息,包括它的當前狀態、分配給它的資源、優先級和其餘相關數據。

在整個生命週期中,進程老是在一些狀態之間轉換。最重要的狀態有就緒態、運行態和阻塞態。一個就緒態進程是指當前沒有執行但已作好了執行準備的進程,只要操做系統調度到它就當即能夠執行;運行態進程是指當前正在被處理器執行的進程,在多處理器系統中,會有多個進程處於這種狀態;阻塞態進程正在等待某一事件的完成,如一次I/O 操做。

一個正在運行的進程可被一個在進程外發生且被處理器識別的中斷事件打斷,或者被執行操做系統的系統調用打斷。不論哪一種狀況,處理器都執行一次模式切換,把控制轉交給操做系統例程。操做系統在完成必需的操做後,能夠恢復被中斷的進程或者切換到別的進程。

相關文章
相關標籤/搜索