直接使用系統呼叫
我對作業系統中的系統呼叫有很大的困惑。根據“作業系統概念第9”一書,提到(在第63頁):
然而,大多數程序員從來沒有看到過這種級別的細節。通常,應用程序開發人員根據應用程序程式介面(API)設計程序。
在幕後,構成 API 的函式通常代表應用程序程序員調用實際的系統呼叫。
這意味著,作為程序員,我們不直接使用系統呼叫。但是,我看到了教如何直接使用系統呼叫的影片,比如這個,它訪問 read|() 和 write() 系統呼叫。所以系統呼叫可以直接使用,也可以使用 API 或兩者都使用??
如果沒有額外的上下文,引用所指的抽象級別並不完全清楚。但是,如果是在談論作業系統的設計概念,那可能是在談論更低的層。
你有沒有問過自己打電話時實際發生
write()
了什麼?系統庫可能會對這些值進行一些完整性檢查,然後可能最終將它們交給作業系統核心。這是你開始真正深入雜草的地方。它究竟如何做到這一點將取決於您的作業系統,甚至它執行的特定處理器架構。例如,Linux 在內部使用
syscall()
向核心發送系統呼叫信號。但是你可能再一次正確地問——syscall()
現在做什麼?非常粗略地,它將您的參數以標準化形式儲存在某處,然後執行一個特殊的處理器指令,該指令切換到特權模式並跳轉到某處作業系統核心中的系統呼叫處理程序。現在沒有什麼能阻止你刪除所有這些中間人,只需將你的參數放在正確的處理器寄存器中,然後自己執行這條指令。沒有規定說你必須使用
write()
,甚至syscall()
. 這些功能只是方便的功能,因為syscall()
可以在每個 Linux 上工作,無論處理器如何;並且write()
可以在任何機器上工作,無論作業系統如何。我懷疑這可能就是你的書所談論的,如果它談論的是作業系統設計的話。作為開發人員,您**不需要使用這些功能,但在絕大多數情況下您想要使用。但是,這些功能本身必須由設計人員為您的作業系統的標準庫實現。它們本身就是 API——標準化的介面,使您不必處理處理器內部。
呼叫系統呼叫的 API 是用程式碼編寫的,例如 C 和內聯彙編的混合。如果您願意,可以將相同或類似的程式碼放入應用程序中。
這是很少做的。該技術用於展示程序,以顯示完全獨立的執行檔在沒有庫依賴關係的情況下可以有多小,但可以做一些有用的事情。
為非 C 語言的執行時工作的人可能會選擇使用原始系統呼叫來避免對 C 庫的依賴。
在 GNU/Linux 世界中,核心和使用者空間幾乎是完全獨立的項目。可以想像這樣一種情況,即開發了一些有用的系統呼叫,應用程序想要使用,但應用程序必須在 C 庫較舊的系統中執行,並且不將該系統呼叫作為 API 公開(但其核心是較新並具有系統呼叫)。在這種情況下,應用程序可以使用系統呼叫的唯一方法是自己發出它。
在某些情況下,API 不直接對應於底層系統呼叫,並且出於性能等各種原因,應用程序開發人員決定將這些系統呼叫掌握在自己手中。
例如,在 GNU/Linux 上,POSIX 函式
opendir
和readdir
,用於在目錄上打開類似流的對象並逐個讀取目錄條目,被實現為getdents
系統呼叫:用於將整批目錄條目讀取到數組中的函式. 有人可能有興趣直接使用這樣的東西,而不是通過一對一的 API。注意手冊頁
getdents
:SYNOPSIS int getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count); int getdents64(unsigned int fd, struct linux_dirent64 *dirp, unsigned int count); [...] NOTES Glibc does not provide a wrapper for these system calls; call them using syscall(2). You will need to define the linux_dirent or linux_dirent64 struc‐ ture yourself. However, you probably want to use readdir(3) instead.