《linux內核設計與實現》第五章

第五章 系統調用linux

1、與內核通訊編程

  系統調用在用戶空間進程和硬件設備之間添加了一箇中間層。做用安全

  • 爲用戶空間提供了一種硬件的抽象接口。
  • 系統調用保證了系統的穩定和安全。
  • 每一個進程都運行在虛擬系統中,而在用戶空間和系統的其他部分提供這樣一層公共接口,也是出於這種考慮。

  在Linux中,系統調用是用戶空間訪問內核的惟一手段;除異常和陷入外,它們是內核惟一的合法入口。函數

2、API、POSIX和C庫性能

  通常狀況下,應用程序經過在用戶空間實現的應用編程接口(API)而不是直接經過系統調用來編程。spa

  一個API定義了一組應用程序使用的編程接口。由於API實際上不須要和系統調用對應(API能夠在各類不一樣的操做系統上實現),一個API能夠實現成一個系統調用,也能夠經過調用多個系統調用來實現,也能夠徹底不用。操作系統

  POSIX、API、C庫及系統調用關係以下:翻譯

  在Unix世界中最流行的應用編程接口是給予POSIX標準的設計

  C庫實現了大部分的POSIX標準API.指針

3、系統調用

  要訪問系統調用(在Linux中常稱做syscall),一般經過C庫中定義的函數調用來進行。

  的返回值表示錯誤,0值一般表示成功。系統調用在出現錯誤時C庫會把錯誤碼寫入errno全局變量,經過調用perror()庫函數,能夠把該變量翻譯成用戶能夠理解的錯誤字符串。

例如:獲取進程ID號的系統調用getpid()

 asmlinkage long sys_getpid(void)   {

    return current->tgid;

}

  • asmlinkage限定詞是編譯器指令,通知編譯器僅從堆棧中提取函數的參數(全部的系統調用都須要這個限定詞);
  • 內核返回long,用戶空間返回int,是爲了保證32位/64位系統兼容;
  • get_pid在內核被定義爲sys_getpid(),linux中全部系統調用都是如此定義的,bar()被定義爲sys_bar()。

  一、系統調用號

    Linux中,每一個系統調用號被賦予一個惟一的系統調用號,進程不會說起系統調用名稱,而是用系統調用號來關聯具體的系統調用。系統調用號一旦分配就不能再改變;若是一個系統調用被刪除,它所佔用的系統調用號也不允

  許被回收利用。Linux有一個「未實現」系統調用sys_ni_syscall(),來補缺已經刪除的調用號。

  二、系統調用的性能

  Linux系統調用比其餘許多操做系統執行得要快:Linux很短的上下文切換時間,系統調用處理程序和每一個系統調用自己也都很是簡潔。

4、系統調用處理程序

  用戶空間的程序沒法直接執行內核代碼,經過軟中斷的機制通知內核須要執行系統調用。經過軟中斷引起一個異常,促使系統切換到內核態,執行異常處理程序代碼;這個異常處理程序就是系統調用處理程序system_call()。

x86系統上軟中斷是中斷號128,經過int $0x80指令觸發該中斷system_call()。

  • 找到指定的系統調用

  在x86上,系統調用號是經過eax寄存器傳遞給內核的。

  • 參數傳遞

  在x86-32系統上,ebx,ecx,edx,esi和edi依次存放前五個參數,若須要六個以上參數,用單獨寄存器指向這些參數在用戶空間地址的指針。經過eax存放返回值。

5、系統調用的實現

  一、實現系統調用

  • 決定用途,每一個系統調用功能應該單一明確,不提倡多用途系統調用;
  • 系統調用參數,返回值和錯誤碼都要明確;
  • 設計接口時儘可能爲未來多作考慮,不要對機器的字節長度和字節序作假設。

  二、參數驗證

  • 檢查全部的參數是否合法有效,最重要的一種檢查就是檢查用戶提供的指針是否有效。
  • 在接收一個用戶空間的指針以前,內核必須保證:

    1)指向用戶空間內存的指針,內核不能直接訪問;

    2)指針指向的內存在用戶進程空間裏,內核不能讀其餘進程空間;

    3)內存不能繞過訪問限制:可讀內存標記爲可讀,可寫標記爲可寫,可執行標記爲可執行。

  • 內核提供了兩個方法來完成必須的檢查和內核空間與用戶空間之間數據的來回拷貝:

    1)爲了向用戶空間寫入數據內核提供了copy_to_user();

    2)爲了從用戶空間讀取數據內核提供了copy_from_user()。

    3)都是把第二個參數指定位置數據傳送到第一個參數指定位置,長度由第三個參數決定。若是執行失敗,兩者都返回未完成拷貝的數據的字節數,成功返回0。

    4)copy_to_user()和copy_from_user()均可能引發阻塞形成進程休眠。

  • 最後一項檢查針對是否有合法權限。

 6、系統調用上下文

  內核在執行系統調用的時候處於進程上下文,urrent指針指向引起系統調用的那個進程。

  在進程上下文中,內核能夠休眠,能夠被搶佔。因此係統調用必須是可重入的。

  一、綁定一個系統調用的最後步驟

  •  在系統調用表中加入表項;
  • 系統調用號定義於<asm/unistd.h>中;
  • 編譯進內核映像,放入kernel/下的相關文件。

  二、從用戶空間訪問系統調用:

  • 系統調用靠C庫支持。
  • Linux自己提供了一組宏,用於直接對系統調用進行訪問;這些宏是_syscalln(),n的範圍是0-6,表明須要傳遞給系統調用的參數個數。

  三、採用系統調用做爲實現方式

優勢有:

  • 系統調用建立容易,且使用方便;
  • Linux系統調用高性能顯而易見。

缺點是:

  • 須要一個系統調用號,這個須要官方分配;
  • 系統調用被加入穩定內核固化後,接口不能改變;
  • 須要將系統調用分別分配到各類體系結構去;
  • 在腳本中不容易調用系統調用,也不能從文件系統直接訪問系統調用;
  • 在主內核樹以外很難維護;
  • 若是隻進行簡單信息交換,系統調用大材小用了。

替代方法:

  • 實現一個設備節點,並對此實現read()和write(),ioctl()來進行操做;
  • 像信號量這樣的某些接口,能夠用文件描述符來表示;
  • 把增長的信息做爲一個文件放在sysfs的合適位置。

 7、總結

      這一章講了系統調用的知識,Linux儘可能使系統調用簡潔,事實上Linux已是一個相對穩定而且功能已經較爲完善的操做系統。本章的內容與視頻上的知識相輔相成,有助於咱們對系統調用的理解,咱們瞭解了系統調用是什麼,以及他們與API和庫函數的關係。還有實現系統調用的過程,和參數驗證,最後還總結了採用系統調用做爲實現方式的利弊和代替方法。有助於咱們理解和掌握。

相關文章
相關標籤/搜索