CHAPTER 5 系統調用
5.1 與內核通訊
5.2 API、POSIX和C庫
通常狀況下,應用程序經過在用戶空間實現的應用編程接口(API)而不是直接經過系統調用來編程。安全
-
系統調用的支持方式:函數
1.系統調用依靠C庫支持。用戶程序經過包含標準頭文件並和C庫連接,就可使用系統調用。性能
2.C庫也實現了Unix系統的主要API。此外,C庫還提供了POSIX的大部分API。學習
-
API、POSIX、C庫以及系統調用之間的關係:操作系統
-
在Unix世界中,最流行的應用編程接口是基於POSIX標準的。翻譯
5.3 系統調用
5.3.1 系統調用
- 要訪問系統調用(syscall),一般經過C庫中定義的函數調用來進行。
- 系統調用經過一個long類型的返回值來表示成功或者錯誤。一般,但也不絕對,用一個負的返回值來代表錯誤。返回一個0值一般代表成功。系統調用在出現錯誤的時候C庫會把錯誤碼寫入errno全局變量,經過調用perror()庫函數,能夠把該變量翻譯成用戶能夠理解的錯誤字符串。
- 系統調用在用戶空間和內核空間有不一樣的返回值類型,在用戶空間爲int,在內核空間爲long
5.3.2 系統調用號
- 當用戶空間的進程執行一個系統調用時,就用系統調用號指明到底執行哪一個系統調用。進程不會說起系統調用的名稱。
- 系統調用號獨一無二,一旦分配就不能再有任何變動。不然編譯好的應用程序就會崩潰。
- Linux有一個「未實現」系統調用sys_ni_syscall(),它除了返回-ENOSYS外不作任何其餘工做,這個錯誤號就是專門針對無效的系統調用而設的。
- 內核記錄了系統調用表中的全部已註冊過的系統調用的列表,存儲在sys_call_table中。
5.3.3. 系統調用的性能
- Linux系統調用比其餘許多操做系統執行得要快。 - 緣由:設計
- 上下文切換時間短。
- 系統調用處理程序和每一個系統調用自己也都很是簡潔。
5.4 系統調用處理程序
5.4.1 指定恰當的系統調用
- 通知內核的機制是軟中斷實現的:經過引起一個異常來促使系統切換到內核態去指向異常處理程序,而此時的異常處理程序就是系統調用的處理程序。
- 在x86系統上預約義的軟中斷是中斷號128,經過int $0x80指令觸發該中斷。
- 用戶程序沒法直接執行內核代碼,它們也不能直接調用內核空間中的代碼
5.4.2 參數傳遞
- 在陷入內核態以前,用戶空間就把相應的系統調用號傳給eax;這樣系統調用處理程序一旦運行,就能夠從eax中獲得數據
- 在x86—32系統上,ebx,ecx,edx,esi和edi按順序存放前五個參數。須要6個及以上參數,應用一個單獨的寄存器存放指向這些參數在用戶空間地址的指針。
- 給用戶空間的返回值也經過寄存器傳遞。在x86系統上,它存放在eax寄存器中。
5.5 系統調用的實現
5.5.1 實現系統調用
- 第一步,明確系統調用的用途
- 新系統調用的參數、返回值和錯誤碼都應該清晰;接口也要力求簡潔、參數儘量少。
- 系統調用設計得越通用越好。
- 提供機制而不是策略。
- 時刻注意可移植性和健壯性。
5.5.2 參數驗證
- 驗證參數是否合法有效
-
驗證指針是否有效指針
• 指向的區域屬於用戶空間;
• 指向的區域在進程的地址空間中(不容許訪問其餘進程空間);
• 進程不能繞過內存訪問限制。
-
驗證方法:
- 使用內核提供的copytouser()以及copyfromuser()檢查從用戶空間拷貝或者向其中寫入數據是否成功(可能引發阻塞;好比當發生缺頁中斷的時候)
- 使用capale()函數檢查函數是否有權對指定的資源進行操做(若是不能的話則返回0)
5.6 系統調用上下文
- 內核在執行系統調用時處於進程上下文。current指針指向當前任務,即引起系統調用的那個進程。
- 在進程上下文中,內核能夠休眠而且能夠被搶佔。
- 當系統調用返回時,控制權仍然在system_call()中,它最終會負責切換到用戶空間,並讓用戶進程繼續執行下去。
5.6.1 綁定一個系統調用的最後步驟
- 在系統調用表的最後加入一個表項。
- 對於所支持的各類體系結構,系統調用號都必須定義於<asm/unistd.h>中。
- 系統調用必須被編譯進內核映像(不能被編譯成模塊)。放入kernel/下的一個相關文件中便可。
-
系統調用形式:
- asmlinkage long sys_getpid(void)//以getpid()函數爲例
- 【asmlinkage限定詞是一個編譯指令,通知編譯器僅從棧中提取該函數的參數】
5.6.2 從用戶空間訪問系統調用
- Linux自己提供了一組宏,用於直接對系統調用進行訪問,即_syscalln();其中n是傳遞給系統調用的參數個數
- 對每個宏而言,都有2+2*n個參數:第一個是系統調用返回值類型;第二個是系統調用名稱;之後是每一個參數的類型和名稱
- 系統調用靠C庫支持,用戶程序經過包含標準頭文件並和C庫連接,就可使用系統調用。
5.6.3 爲何不經過系統調用的方式實現
-
創建一個新的系統調用的好處:
- 系統調用建立容易且使用方便
- linux系統調用的高性能顯而易見。
-
問題是:
- 你須要一個系統調用號,而這須要一個內核在處於開發版本的時候由官方分配給你。
- 系統調用被加入穩定內核後就被固化了,爲了不應用程序的崩潰,它的接口不容許作運動。
- 須要將系統調用分別註冊到每一個須要支持的體系結構中去。
- 在腳本中不容易調用系統調用,也不能從文件系統直接訪問系統調用。
- 若是僅僅進行簡單的信息交換,系統調用就大材小用了
-
方法:
- 實現一個設備節點,並對此實現read()和write()。使用ioctl()對特定的設置進行操做或者對特定的信息進行檢索。
- 像信號量這樣的某些接口,能夠用文件描述符來表示,所以也就能夠按上述方式對其進行操做。
- 把增長的信息做爲一個文件放在sysfs的合適位置。
小結
在本章中,學到了系統調用究竟是什麼,它們與庫函數和應用程序接口有什麼關係等等。。。最後又學習了實現系統調用的優缺點讓我瞭解的更透徹了一點。
參考資料
《linux內核設計與實現》原書第三版