系統調用類型(六大類)

系統調用大致可分爲六大類:
進程控制(process control)
文件管理(file manipulation)
設備管理(device manipulation)
信息維護(information maintenance)
通信(communication)
保護(protection)

進程控制

執行程序應能正常(end())或異常(abort())停止執行。如果一個系統調用異常停止當前執行的程序,或者程序運行遇到問題並引起錯誤陷阱,那麼有時轉儲內存到磁盤,並生成錯誤信息。內存信息轉儲到磁盤後,可用調試器(debugger)來確定問題原因(調試器爲系統程序,用以幫助程序員發現和糾正錯誤(bug))。

無論是正常情況還是異常情況,操作系統都應將控制轉到調用命令解釋程序。命令解釋程序接着讀入下個命令。對於交互系統,命令解釋程序只是簡單讀入下個命令,而假定用戶會採取合適命令以處理錯誤。對於 GUI 系統,彈出窗口可用於提醒用戶出錯,並請求指引。對於批處理系統,命令解釋程序通常終止整個作業,並繼續下個作業。當出現錯誤時,有的系統可能允許特殊的恢復操作。

如果程序發現輸入有錯並且想要異常終止,那麼它也可能需要定義錯誤級別。錯誤越嚴重,錯誤參數的級別也越高。通過將正常終止的錯誤級別定義爲 0,可以把正常和異常終止放在一起處理。命令解釋程序或後面的程序可以利用這種錯誤級別來自動確定下個動作。

執行一個程序的進程或作業可能需要加載(load())和執行(execute())另一個程序。這種功能允許命令解釋程序來執行一個程序,該命令可以通過用戶命令、鼠標點擊或批處理命令來給定。一個有趣的問題是:加載程序終止時會將控制返回到哪裏?與之相關的問題是:原有程序是否失去或保存了,或者可與新的程序一起併發執行?

如果新程序終止時控制返回到現有程序,那麼必須保存現有程序的內存映像。因此,事實上創建了一個機制,以便一個程序調用另一個程序。如果兩個程序併發繼續,那麼也就創建了一個新作業或進程,以便多道執行。通常,有一個系統調用專門用於這一目的(create_process() 或 submit_job())。

如果創建了一個新的作業或進程或者一組作業或進程,那麼我們應能控制執行。這種控制要能判定和重置進程或作業的屬性,包括作業的優先級、最大允許執行時間等(get_ process_attributes() 和 set_process_attributes())。如果發現創建的進程或作業不正確或者不再需要,那麼也要能終止它(terminate_process())。

創建了新的作業或進程後,可能要等待其執行完成,也可能要等待一定時間(wait_time())。更有可能要等待某個事件的出現(wait_event())。當事件出現時,作業或進程就會響應(signal_event())。

通常,兩個或多個進程會共享數據。爲了確保共享數據的完整性,操作系統通常提供系統調用,以允許一個進程鎖定(lock)共享數據。這樣,在解鎖之前,其他進程不能訪問該數據。通常,這樣的系統調用包括 acquire_lock() 和 release_lock()。這類系統調用用於協調併發進程,將在後續章節詳細討論。

進程和作業控制差異很大,這裏通過兩個例子加以說明:一個涉及單任務系統,另一個涉及多任務系統。

MS-DOS 操作系統是個單任務的系統,在計算機啓動時它就運行一個命令解釋程序(圖 1a)。由於 MS-DOS 是單任務的,它採用了一種簡單方法來執行程序而且不創建新進程。它加載程序到內存,並對自身進行改寫,以便爲新程序提供儘可能多的空間(圖 1b)。
在這裏插入圖片描述
MS-DOS 執行狀態
圖 1 MS-DOS 執行狀態

接着,它將指令指針設爲程序的第一條指令。然後,運行程序,或者錯誤引起中斷,或者程序執行系統調用來終止。無論如何,錯誤代碼會保存在系統內存中以便以後使用。之後,命令解釋程序中的尚未改寫部分重新開始執行。它首先從磁盤中重新加載命令解釋程序的其他部分。然後,命令解釋程序會向用戶或下個程序提供先前的錯誤代碼。

FreeBSD(源於 Berkeley UNIX)是個多任務系統。在用戶登錄到系統後,用戶所選的外殼就開始運行。這種外殼類似於 MS-DOS 外殼:按用戶要求,接受命令並執行程序。不過,由於 FreeBSD 是多任務系統,命令解釋程序在另一個程序執行,也可繼續執行(圖 2)。

運行多個程序的FreeBSD
在這裏插入圖片描述
圖 2 運行多個程序的 FreeBSD

爲了啓動新進程,外殼執行系統調用 fork()。接着,所選程序通過系統調用 exec() 加載到內存,程序開始執行。根據命令執行方式,外殼要麼等待進程完成,要麼後臺執行進程。對於後一種情況,外殼可以馬上接受下個命令。當進程在後臺運行時,它不能直接接受鍵盤輸入,這是因爲外殼已在使用鍵盤。因此 I/O 可通過文件或 GUI 來完成。

同時,用戶可以讓外殼執行其他程序,監視運行進程狀態,改變程序優先級等。當進程完成時,它執行系統調用 exit() 以終止,並將 0 或非 0 的錯誤代碼返回到調用進程。這一狀態(或錯誤)代碼可用於外殼或其他程序。後續章節將通過一個使用系統調用 fork() 和 exec() 的程序例子來討論進程。

文件管理

下面,我們討論一些有關文件的常用系統調用。

首先要能創建(create())和刪除(delete())文件。這兩個系統調用需要文件名稱,還可能需要文件的一些屬性。一旦文件創建後,就會打開(open())並使用它,也會讀(read())、寫(write())或重定位(reposition())(例如,重新回到文件開頭,或直接跳到文件末尾)。最後,需要關閉(close())文件,表示不再使用它了。

如果採用目錄結構來組織文件系統的文件,那麼也會需要同樣的目錄操作。另外,不管是文件還是目錄,都要能對各種屬性的值加以讀取或設置。文件屬性包括:文件名、文件類型、保護碼、記賬信息等。

針對這一功能,至少需要兩個系統調用:獲取文件屬性(get_file_attributes())和設置文件屬性(set_file_attributes())。有的操作系統還提供其他系統調用,如文件的移動(move())和複製(copy())。還有的操作系統通過代碼或系統調用來完成這些 API 的功能。其他的操作系統可能通過系統程序來實現這些功能。如果系統程序可被其他程序調用,那麼這些系統程序也就相當於 API。

設備管理

進程執行需要一些資源,如內存、磁盤驅動、所需文件等。如果有可用資源,那麼系統可以允許請求,並將控制交給用戶程序;否則,程序應等待,直到有足夠可用的資源爲止。

操作系統控制的各種資源可看作設備。有的設備是物理設備(如磁盤驅動),而其他的可當作抽象或虛擬的設備(如文件)。多用戶系統要求先請求(request())設備,以確保設備的專門使用。在設備用完後,要釋放(release())它。這些函數類似於文件的系統調用 open() 和 close()。其他操作系統對設備訪問不加管理。這樣帶來的危害是潛在的設備爭用以及可能發生的死鎖,這將在後續章節中討論。

在請求了設備(並得到)後,就能如同對文件一樣,對設備進行讀(read())、寫(write())、重定位(reposition())。事實上,I/O 設備和文件極爲相似,以至於許多操作系統如 UNIX 都將這兩者組合成文件-設備結構。這樣,一組系統調用不但用於文件而且用於設備。有時,I/O 設備可通過特殊文件名、目錄位置或文件屬性來辨認。

用戶界面可以讓文件和設備看起來相似,即便內在系統調用不同。在設計、構建操作系統和用戶界面時,這也是要加以考慮的。

信息維護

許多系統調用只不過用於在用戶程序與操作系統之間傳遞信息。例如,大多數操作系統都有一個系統調用,以便返回當前的時間(time())和日期(date())。還有的系統調用可以返回系統的其他信息,如當前用戶數、操作系統版本、內存或磁盤的可用量等。

還有一組系統調用幫助調試程序。許多系統都提供用於轉儲內存(dump())的系統調用。對於調試,這很有用。程序 trace 可以列出程序執行時的所有系統調用。甚至微處理器都有一個 CPU 模式,稱爲單步(single step),即 CPU 每執行一條指令都會產生一個陷阱。調試器通常可以捕獲到這些陷阱。

許多操作系統都提供程序的時間曲線(time profile),用於表示在特定位置或位置組合上的執行時間。時間曲線需要跟蹤功能或固定定時中斷。當定時中斷出現時,就會記錄程序計數器的值。如有足夠頻繁的定時中斷,那麼就可得到花在程序各個部分的時間統計信息。

再者,操作系統維護所有進程的信息,這些可通過系統調用來訪問。通常,也可用系統調用重置進程信息(get_process_attributes() 和 set_process_attributes ())。

通信

進程間通信的常用模型有兩個:消息傳遞模型和共享內存模型。

對於消息傳遞模型(message-passing model),通信進程通過相互交換消息來傳遞信息。進程間的消息交換可以直接進行,也可以通過一個共同郵箱來間接進行。在開始通信前,應先建立連接。應知道另一個通信實體名稱,它可能是同一系統的另一個進程,也可能是通過網絡相連的另一計算機的進程。

每臺網絡計算機都有一個主機名(hostname),這是衆所周知的。另外,每臺主機也都有一個網絡標識符,如IP地址。類似地,每個進程有進程名(process name),它通常可轉換成標識符,以便操作系統引用。系統調用 get_hostid() 和 get_processid() 可以執行這類轉換。這些標識符再傳給通用系統調用 open() 和 close()(由文件系統提供),或專用系統調用 open_connection() 和 close_connection(),這取決於系統通信模型。

接受進程應通過系統調用 accept_connection() 來許可通信。大多數可接受連接的進程爲專用的守護進程(daemon),即專用系統程序。它們執行系統調用 wait_for_connection(),在有連接時會被喚醒。通信源稱爲客戶機(client),而接受後臺程序稱爲服務器(server),它們通過系統調用 read_message() 和 write_message() 來交換消息。系統調用 close_connection() 終止通信。

對於共享內存模型(shared-memory model),進程通過系統調用 shared_memory_create() 和 shared_memory_attach() 創建共享內存,並訪問其他進程擁有的內存區域。

注意,操作系統通常需要阻止一個進程訪問另一個進程的內存。共享內存要求兩個或多個進程都同意取消這一限制,這樣它們就可通過讀寫共享區域的數據來交換信息。這種數據的類型是由這些進程來決定的,而不受操作系統的控制。進程也負責確保不會同時向同一個地方進行寫操作。

上面討論的兩種模型常用於操作系統,而且大多數系統兩種都實現了。消息傳遞對少量數據的交換很有用,因爲沒有衝突需要避免。與用於計算機間的共享內存相比,它也更容易實現。共享內存在通信方面具有高速和便捷的特點,因爲當通信發生在同一計算機內時,它可以按內存傳輸速度來進行。不過,共享內存的進程在保護和同步方面有問題。

保護

保護提供控制訪問計算機的系統資源的機制。過去,只有多用戶的多道計算機系統纔要考慮保護。隨着網絡和因特網的出現,所有計算機(從服務器到手持移動設備)都應考慮保護。

通常,提供保護的系統調用包括 set_permission() 和 get_permission(),用於設置資源(如文件和磁盤)權限。系統調用 allow_user() 和 deny_user() 分別用於允許和拒絕特定用戶訪問某些資源。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章