現(xiàn)代操作系統(tǒng)中,內(nèi)核提供了用戶進(jìn)程和內(nèi)核進(jìn)程交互的一組接口,,讓app可以受限的訪問硬件資源,,提供進(jìn)程間通信機(jī)制,實(shí)際上主要是為了保證系統(tǒng)穩(wěn)定可靠,,避免應(yīng)用程序do whatever they want. 1.與內(nèi)核通信 系統(tǒng)調(diào)用在用戶空間進(jìn)程和硬件設(shè)備之間添加了一個中間層,,主要作用: ①為用戶空間提供了一種硬件的抽象接口; ②保證了系統(tǒng)的穩(wěn)定和安全,,可以給予權(quán)限,,用戶對訪問進(jìn)行裁決; ③每個進(jìn)程都運(yùn)行在虛擬系統(tǒng)中,; 在Linux中,,系統(tǒng)調(diào)用是用戶空間訪問內(nèi)核的唯一手段,;除異常和陷入外,是內(nèi)核唯一的合法入口,;實(shí)際上像設(shè)備文件和/proc之類的方式,也是通過系統(tǒng)調(diào)用進(jìn)行訪問的,。
2 API,、POSIX和C庫 應(yīng)用程序通過在用戶空間實(shí)現(xiàn)的應(yīng)用編程接口(API),而不是直接通過系統(tǒng)調(diào)用來編程,。 因?yàn)?span lang="EN-US">API實(shí)際上不需要和系統(tǒng)調(diào)用對應(yīng),,一個API可以實(shí)現(xiàn)成一個系統(tǒng)調(diào)用,也可以通過調(diào)用多個系統(tǒng)調(diào)用來實(shí)現(xiàn),,也可以完全不用,。POSIX、API,、C庫及系統(tǒng)調(diào)用關(guān)系如下 程序員只跟API打交道,,內(nèi)核只跟系統(tǒng)調(diào)用打交道;即內(nèi)核提供機(jī)制,,API提供策略,。 C庫實(shí)現(xiàn)了大部分的POSIX標(biāo)準(zhǔn)API.
3.系統(tǒng)調(diào)用 系統(tǒng)調(diào)用一般用返回0來表示成功,返回負(fù)數(shù)表明錯誤,錯誤碼寫入errno全局變量,用peeror()庫函數(shù)可以把錯誤碼轉(zhuǎn)變成錯誤字符串. 舉一例,獲取進(jìn)程ID號的系統(tǒng)調(diào)用getpid() 點(diǎn)擊(此處)折疊或打開
①asmlinkage限定詞是編譯器指令,告知編譯器僅從堆棧中提取函數(shù)的參數(shù),; ②內(nèi)核返回long,,用戶空間返回int,是為了保證32位/64位系統(tǒng)兼容,; ③get_pid在內(nèi)核被定義為sys_getpid(),,內(nèi)核對系統(tǒng)調(diào)用都是如此定義的; (1)系統(tǒng)調(diào)用號 Linux中,,每個系統(tǒng)調(diào)用號被賦予一個唯一的系統(tǒng)調(diào)用號,,進(jìn)程不會提及系統(tǒng)調(diào)用名稱,而是用系統(tǒng)調(diào)用號來關(guān)聯(lián)具體的系統(tǒng)調(diào)用,。 一個系統(tǒng)調(diào)用號一旦被分配,不能隨意變更,;用sys_ni_syscall()來補(bǔ)缺已經(jīng)刪除的調(diào)用號,; 系統(tǒng)調(diào)用號保持在unsigned long sys_call_table[NR_syscalls]; (2)系統(tǒng)調(diào)用的性能 Linux上下文切換時間很短,,進(jìn)出內(nèi)核都被優(yōu)化的簡潔高效;系統(tǒng)調(diào)用處理程序和每個系統(tǒng)調(diào)用本身都非常簡潔,,所以Linux系統(tǒng)調(diào)用比許多其他操作系統(tǒng)都執(zhí)行的快,。 (3)系統(tǒng)調(diào)用處理程序 通過軟中斷引發(fā)一個異常,促使系統(tǒng)切換到內(nèi)核態(tài),,執(zhí)行異常處理程序代碼,;這個異常處理程序就是系統(tǒng)調(diào)用處理程序system_call(),。 ①找到指定的系統(tǒng)調(diào)用 X86上是通過eax把系統(tǒng)調(diào)用號傳給內(nèi)核,system_call()通過查找sys_call_table[]找到對應(yīng)的系統(tǒng)調(diào)用 ②參數(shù)傳遞 Ebx,ecx,edx,esi和edi依次存放前五個參數(shù),,若需要六個以上參數(shù),用單獨(dú)寄存器指向這些參數(shù)在用戶空間地址的指針,。通過eax存放返回值。
4.系統(tǒng)調(diào)用的實(shí)現(xiàn) (1)決定用途,,每個系統(tǒng)調(diào)用功能應(yīng)該單一明確,不提倡多用途系統(tǒng)調(diào)用,。系統(tǒng)調(diào)用參數(shù),返回值和錯誤碼都要明確,,不要對機(jī)器字節(jié)長度和字節(jié)序做假設(shè),。 (2)參數(shù)驗(yàn)證:內(nèi)核必須保證 ①指向用戶空間內(nèi)存的指針,,內(nèi)核不能直接訪問; ②指針指向的內(nèi)存在用戶進(jìn)程空間里,,內(nèi)核不能讀其他進(jìn)程空間; ③內(nèi)存不能繞過訪問限制:可讀內(nèi)存標(biāo)記為可讀,,可寫標(biāo)記為可寫,可執(zhí)行標(biāo)記為可執(zhí)行 內(nèi)核用copy_to_user()和copy_from_user()來從用戶空間讀寫數(shù)據(jù),,都是把第二個參數(shù)指定位置數(shù)據(jù)傳送到第一個參數(shù)指定位置,長度由第三個參數(shù)決定,。執(zhí)行失敗,,返回未傳送字節(jié),成功返回0,。copy_to_user()和copy_from_user()都可能引起休眠。 ④檢查權(quán)能,,針對合法權(quán)限,比如if (!capable(CAP_SYS_BOOT)) return –EPERM; (3)內(nèi)核執(zhí)行系統(tǒng)調(diào)用時處于進(jìn)程上下文,,current指針指向引發(fā)系統(tǒng)調(diào)用的那個進(jìn)程。能夠休眠,,所以系統(tǒng)調(diào)用必須是可重入的,。 (4)往系統(tǒng)添加一個系統(tǒng)調(diào)用的一個簡單實(shí)例 ①添加系統(tǒng)調(diào)用名字函數(shù)名字sys_mytest,一般在calls.S或者entry.S /* 320 */ .long sys_get_mempolicy .long sys_set_mempolicy .long sys_mytest ②在unistd.h添加系統(tǒng)調(diào)用號,322 #define __NR_get_mempolicy (__NR_SYSCALL_BASE+320) #define __NR_set_mempolicy (__NR_SYSCALL_BASE+321) #define __NR_mytest (__NR_SYSCALL_BASE+322) ③實(shí)現(xiàn)系統(tǒng)調(diào)用函數(shù) 點(diǎn)擊(此處)折疊或打開
④在syscalls.h做系統(tǒng)調(diào)用函數(shù)聲明 點(diǎn)擊(此處)折疊或打開
⑤app測試 點(diǎn)擊(此處)折疊或打開
①系統(tǒng)調(diào)用創(chuàng)建容易,且使用方便,; ②Linux系統(tǒng)調(diào)用高性能顯而易見 缺點(diǎn)是: ①需要一個系統(tǒng)調(diào)用號,這個需要官方分配 ②系統(tǒng)調(diào)用被加入穩(wěn)定內(nèi)核固化后,,接口不能改變,; ③需要將系統(tǒng)調(diào)用分別分配到各種體系結(jié)構(gòu)去(與硬件相關(guān)) ④在腳本中不容易調(diào)用系統(tǒng)調(diào)用,也不能從文件系統(tǒng)直接訪問系統(tǒng)調(diào)用 ⑤在主內(nèi)核樹之外很難維護(hù) ⑥如果只進(jìn)行簡單信息交換,,系統(tǒng)調(diào)用大材小用了,。所以盡管建立一個系統(tǒng)調(diào)用非常容易,但是不建議這么做,,替代方法: ①實(shí)現(xiàn)一個設(shè)備節(jié)點(diǎn),,并對此實(shí)現(xiàn)read()和write(),,ioctl()來進(jìn)行操作 ②像信號量這樣的某些接口,可以用文件描述符來表示 ③把增加的信息作為一個文件放在sysfs的合適位置
Linux盡量使系統(tǒng)調(diào)用簡潔,,事實(shí)上Linux已經(jīng)是一個相對穩(wěn)定并且功能已經(jīng)較為完善的操作系統(tǒng),。 |
|