作業系統中最基本的概念——庫呼叫和系統呼叫
Unix作業系統設計上的陳述:
理解庫函式的區別和系統呼叫,首先要裡理解Unix的kernel mode和user mode。考慮下面的函式段:
int main()
{
int fd = create("filename",0666);
exit(0);
}
在執行main函式時,是在user mode下執行,當遇到create函式時,繼續在user mode下執行。然後系統將兩個引數"filenam"和"0666"壓入棧中或者某個暫存器,接著執行庫函式create。在庫函式create執行開始,系統仍然處在user mode下,接著系統將create系統呼叫的unique number壓入暫存器(比如說r0),然後執行指令trap(operating system trap)使系統進入kernel mode,並且處理系統呼叫。這時,系統意識到要進行系統呼叫的invoke,於是從暫存器r0中取出create系統呼叫的unique number,從系統呼叫表中查詢得知要invoke的系統呼叫是create,然後執行。執行完畢後返回庫函式create的呼叫,庫函式負責檢查系統呼叫的執行情況(檢查某些暫存器的值),然後庫函式create根據檢查的結果返回相應的值。
在這裡,trap指令類似於一個系統中斷,而系統呼叫create是一個特殊的中斷處理函式(inerrupt handler)。
APUE上的陳述:
所有作業系統都提供多種服務的入口點,由此程式向系統核請求服務。各種版本的Unix都
提供經良好定義的有限數目的入口點,經過這些入口點進入系統核,這些入口點被稱之為
系統呼叫(system call),系統呼叫是我們不能更改的一種Unix特徵。Unix版本7提供了約
50個系統呼叫,4 3+BSD提供了約110個,而SVR4則提供了約120個。
系統呼叫介面總是在Unix程式設計師手冊的第二部分中說明。其定義也包括在C語言中。這與很
多較早期的作業系統是不同的,這些系統按傳統都在機器的組合語言中定義系統核入口點。
Unix所使用的技術是為每條系統呼叫在標準C庫中設定一個具有同樣名字的函式。使用者程序
用標準C呼叫序列來呼叫這些函式,然後,函式用系統所要求的技術呼叫相應的系統核服務
。例如函式可將一個或幾個C引數送入通用暫存器,然後執行某個產生軟中斷進入系統核的
機器指令。從應用角度考慮,我們可將系統呼叫視作為C函式。
Unix程式設計師手冊的第三部分定義了程式設計師可以使用的通用函式。雖然這些函式可能會呼叫
一個或幾個系統核的系統呼叫,但是它們並不是系統核的入口點。例如,printf函式會調
用write系統呼叫以進行輸出操作,但函式strcpy(複製一字串)和atoi(變換ASCII為整數
)並不使用任何系統呼叫。
從實施者的角度,系統呼叫和庫函式之間有重大區別,但從使用者角度其區別並不非常重要。
從本書的目的出發,系統呼叫和庫函式在本書中都以正常的C函式的形式出現。兩者都對應
用程式提供服務,但是,我們應當理解,如果希望的話,我們可以代換庫函式,但是通常
我們卻不能代換系統服務。
以儲存器分配函式malloc為例。有多種方法可以進行儲存器分配及與其相關的無用區收集
操作(最佳適應,首次適應等),並不存在對所有程式都最佳的一種技術。Unix系統呼叫中
處理儲存器分配的是sbrk(2),它不是一個通用的儲存器管理器。它增加或減少指定位元組數
的程序地址空間。如何管理該地址空間卻取決於程序。儲存器分配函式malloc(3)實現一
種特定型別的分配。如果我們不喜歡其操作方式,則我們可以定義自己的malloc函式,極
其可能,它還是要呼叫sbrk系統呼叫。事實上,有很多軟體包,它們實現自己的儲存器分
配演算法,但仍使用sbrk系統呼叫。
從中可見,兩者職責不同,相互分開,要核中的系統呼叫分配另外一塊空間給程序,而庫
函式malloc則管理這種空間。
另一個可說明系統呼叫和庫函式之間的差別的例子是,Unix提供決定當前時間和日期的界
面。某些作業系統提供一個系統呼叫以返回時間,而另一個則返回日期。任何特殊的處理
,例如正常時制和日光節約時制之間的轉換,由系統核處理或要求人的幹予。Unix則不同
,它只提供一條系統呼叫,該系統呼叫返回國際標準時公元一九七年一月一日午夜來所以
經過的秒數。對該值的任何解釋,例如將其變換成人們可讀的,使用本地時區的時間和日
期,都留給使用者程序執行。在標準C庫中,提供了若干例程以處理大多數情況。這些庫函式
處理各種細節,例如各種日光節約時演算法。
應用程式可以或者呼叫系統呼叫,或者庫函式,而很多庫函式則會呼叫系統呼叫。
另一個系統呼叫和庫函式之間的差別是:系統呼叫通常提供一種最小介面,而庫函式通常
提供比較複雜的功能。我們從sbrk系統呼叫和malloc庫函式之間的差別中看到了這一點,
在以後當比較不帶快取的I/O庫數(第3章)以及標準I/O標準(在第5章)時,我們還將看到這
種差別。
程序控制系統呼叫(fork,exec和wait)通常由使用者的應用程式直接呼叫。(請回憶程式1.5中
的基本shell)但是為了簡化某些常見的情況,UNIX系統也提供了一些庫函式;例如system
和popen。在8.12節中,我們將說明system函式的一種實現,它使用基本的程序控制系統調
用。在10.18中,我們還將強化這一例項以正確地處理訊號。
為使讀者瞭解大多數程式設計師應用的Unix系統介面,我們不得不既說明系統呼叫,只介紹某
些庫函式。例如若我們只說明sbrk系統呼叫,那麼就會忽略很多應用程式使用的malloc庫函式
。
在本書中,除了一定要將兩者相區分時,我們都將使用術語"函式"來涉及系統呼叫和庫函
數兩者。
函式庫呼叫 |
系統呼叫 |
在所有的ANSI C編譯器版本中,C庫函式是相同的 |
各個作業系統的系統呼叫是不同的 |
它呼叫函式庫中的一段程式(或函式) |
它呼叫系統核心的服務 |
與使用者程式相聯絡 |
是作業系統的一個入口點 |
在使用者地址空間執行 |
在核心地址空間執行 |
它的執行時間屬於“使用者時間” |
它的執行時間屬於“系統”時間 |
屬於過程呼叫,呼叫開銷較小 |
需要在使用者空間和核心上下文環境間切換,開銷較大 |
在C函式庫libc中有大約300個函式 |
在UNIX中大約有90個系統呼叫 |
典型的C函式庫呼叫:system fprintf malloc |
典型的系統呼叫:chdir fork write brk; |