【Linux系统编程】 Linux系统调用概述
系統調用概述
系統調用,顧名思義,說的是操作系統提供給用戶程序調用的一組“特殊”接口。用戶程序可以通過這組“特殊”接口來獲得操作系統內核提供的服務,比如用戶可以通過文件系統相關的調用請求系統打開文件、關閉文件或讀寫文件,可以通過時鐘相關的系統調用獲得系統時間或設置定時器等。
從邏輯上來說,系統調用可被看成是一個內核與用戶空間程序交互的接口——它好比一個中間人,把用戶進程的請求傳達給內核,待內核把請求處理完畢后再將處理結果送回給用戶空間。
系統服務之所以需要通過系統調用來提供給用戶空間的根本原因是為了對系統進行“保護”,因為我們知道 Linux 的運行空間分為內核空間與用戶空間,它們各自運行在不同的級別中,邏輯上相互隔離。所以用戶進程在通常情況下不允許訪問內核數據,也無法使用內核函數,它們只能在用戶空間操作用戶數據,調用用戶空間函數。比如我們熟悉的“hello world”程序(執行時)就是標準的用戶空間進程,它使用的打印函數 printf 就屬于用戶空間函數,打印的字符“hello word”字符串也屬于用戶空間數據。
但是很多情況下,用戶進程需要獲得系統服務(調用系統程序),這時就必須利用系統提供給用戶的“特殊接口”——系統調用了,它的特殊性主要在于規定了用戶進程進入內核的具體位置;換句話說,用戶訪問內核的路徑是事先規定好的,只能從規定位置進入內核,而不準許肆意跳入內核。有了這樣的陷入內核的統一訪問路徑限制才能保證內核安全無誤。我們可以形象地描述這種機制:作為一個游客,你可以買票要求進入野生動物園,但你必須老老實實地坐在觀光車上,按照規定的路線觀光游覽。當然,不準下車,因為那樣太危險,不是讓你丟掉小命,就是讓你嚇壞了野生動物。
系統調用的實現
系統調用是屬于操作系統內核的一部分的,必須以某種方式提供給進程讓它們去調用。CPU 可以在不同的特權級別下運行,而相應的操作系統也有不同的運行級別,用戶態和內核態。運行在內核態的進程可以毫無限制的訪問各種資源,而在用戶態下的用戶進程的各種操作都有著限制,比如不能隨意的訪問內存、不能開閉中斷以及切換運行的特權級別。顯然,屬于內核的系統調用一定是運行在內核態下,但是如何切換到內核態呢?
答案是軟件中斷。軟件中斷和我們常說的中斷(硬件中斷)不同之處在于,它是通過軟件指令觸發而并非外設引發的中斷,也就是說,又是編程人員開發出的一種異常(該異常為正常的異常)。操作系統一般是通過軟件中斷從用戶態切換到內核態。
? ? ? ??
中斷有兩個重要的屬性,中斷號和中斷處理程序。中斷號用來標識不同的中斷,不同的中斷具有不同的中斷處理程序。在操作系統內核中維護著一個中斷向量表(Interrupt Vector Table),這個數組存儲了所有中斷處理程序的地址,而中斷號就是相應中斷在中斷向量表中的偏移量。更多詳細說明請看《系統調用的實現原理》。
系統調用和庫函數的區別
Linux 下對文件操作有兩種方式:系統調用(system call)和庫函數調用(Library functions)。
庫函數由兩類函數組成:
1)不需要調用系統調用
不需要切換到內核空間即可完成函數全部功能,并且將結果反饋給應用程序,如strcpy、bzero 等字符串操作函數。
2)需要調用系統調用
需要切換到內核空間,這類函數通過封裝系統調用去實現相應功能,如 printf、fread等。
系統調用是需要時間的,程序中頻繁的使用系統調用會降低程序的運行效率。當運行內核代碼時,CPU工作在內核態,在系統調用發生前需要保存用戶態的棧和內存環境,然后轉入內核態工作。系統調用結束后,又要切換回用戶態。這種環境的切換會消耗掉許多時間。
庫函數訪問文件的時候根據需要,設置不同類型的緩沖區,從而減少了直接調用 IO 系統調用的次數,提高了訪問效率。緩沖區詳情請看《淺談標準I/O緩沖區》。
這個過程類似于快遞員給某個區域(內核空間)送快遞一樣,快遞員有兩種方式送:
1)來一件快遞就馬上送到目的地,來一件送一件,這樣導致來回走比較頻繁(系統調用)
2)等快遞攢著差不多后(緩沖區),才一次性送到目的地(庫函數調用)
函數庫調用 VS 系統調用
資料參考:http://blog.csdn.net/orange_os
其中有一些函數的作用完全相同,只是參數不同。(可能很多熟悉C++朋友馬上就能聯想起函數重載,但是別忘了Linux核心是用C語言寫的,所以只能取成不同的函數名)。還有一些函數已經過時,被新的更好的函數所代替了(gcc在鏈接這些函數時會發出警告),但因為兼容的原因還保留著,這些函數我會在前面標上“*”號以示區別。
一、進程控制:
| fork | 創建一個新進程 |
| clone | 按指定條件創建子進程 |
| execve | 運行可執行文件 |
| exit | 中止進程 |
| _exit | 立即中止當前進程 |
| getdtablesize | 進程所能打開的最大文件數 |
| getpgid | 獲取指定進程組標識號 |
| setpgid | 設置指定進程組標志號 |
| getpgrp | 獲取當前進程組標識號 |
| setpgrp | 設置當前進程組標志號 |
| getpid | 獲取進程標識號 |
| getppid | 獲取父進程標識號 |
| getpriority | 獲取調度優先級 |
| setpriority | 設置調度優先級 |
| modify_ldt | 讀寫進程的本地描述表 |
| nanosleep | 使進程睡眠指定的時間 |
| nice | 改變分時進程的優先級 |
| pause | 掛起進程,等待信號 |
| personality | 設置進程運行域 |
| prctl | 對進程進行特定操作 |
| ptrace | 進程跟蹤 |
| sched_get_priority_max | 取得靜態優先級的上限 |
| sched_get_priority_min | 取得靜態優先級的下限 |
| sched_getparam | 取得進程的調度參數 |
| sched_getscheduler | 取得指定進程的調度策略 |
| sched_rr_get_interval | 取得按RR算法調度的實時進程的時間片長度 |
| sched_setparam | 設置進程的調度參數 |
| sched_setscheduler | 設置指定進程的調度策略和參數 |
| sched_yield | 進程主動讓出處理器,并將自己等候調度隊列隊尾 |
| vfork | 創建一個子進程,以供執行新程序,常與execve等同時使用 |
| wait | 等待子進程終止 |
| wait3 | 參見wait |
| waitpid | 等待指定子進程終止 |
| wait4 | 參見waitpid |
| capget | 獲取進程權限 |
| capset | 設置進程權限 |
| getsid | 獲取會晤標識號 |
| setsid | 設置會晤標識號 |
回頁首
二、文件系統控制
1、文件讀寫操作
| fcntl | 文件控制 |
| open | 打開文件 |
| creat | 創建新文件 |
| close | 關閉文件描述字 |
| read | 讀文件 |
| write | 寫文件 |
| readv | 從文件讀入數據到緩沖數組中 |
| writev | 將緩沖數組里的數據寫入文件 |
| pread | 對文件隨機讀 |
| pwrite | 對文件隨機寫 |
| lseek | 移動文件指針 |
| _llseek | 在64位地址空間里移動文件指針 |
| dup | 復制已打開的文件描述字 |
| dup2 | 按指定條件復制文件描述字 |
| flock | 文件加/解鎖 |
| poll | I/O多路轉換 |
| truncate | 截斷文件 |
| ftruncate | 參見truncate |
| umask | 設置文件權限掩碼 |
| fsync | 把文件在內存中的部分寫回磁盤 |
2、文件系統操作
| access | 確定文件的可存取性 |
| chdir | 改變當前工作目錄 |
| fchdir | 參見chdir |
| chmod | 改變文件方式 |
| fchmod | 參見chmod |
| chown | 改變文件的屬主或用戶組 |
| fchown | 參見chown |
| lchown | 參見chown |
| chroot | 改變根目錄 |
| stat | 取文件狀態信息 |
| lstat | 參見stat |
| fstat | 參見stat |
| statfs | 取文件系統信息 |
| fstatfs | 參見statfs |
| readdir | 讀取目錄項 |
| getdents | 讀取目錄項 |
| mkdir | 創建目錄 |
| mknod | 創建索引節點 |
| rmdir | 刪除目錄 |
| rename | 文件改名 |
| link | 創建鏈接 |
| symlink | 創建符號鏈接 |
| unlink | 刪除鏈接 |
| readlink | 讀符號鏈接的值 |
| mount | 安裝文件系統 |
| umount | 卸下文件系統 |
| ustat | 取文件系統信息 |
| utime | 改變文件的訪問修改時間 |
| utimes | 參見utime |
| quotactl | 控制磁盤配額 |
回頁首
三、系統控制
| ioctl | I/O總控制函數 |
| _sysctl | 讀/寫系統參數 |
| acct | 啟用或禁止進程記賬 |
| getrlimit | 獲取系統資源上限 |
| setrlimit | 設置系統資源上限 |
| getrusage | 獲取系統資源使用情況 |
| uselib | 選擇要使用的二進制函數庫 |
| ioperm | 設置端口I/O權限 |
| iopl | 改變進程I/O權限級別 |
| outb | 低級端口操作 |
| reboot | 重新啟動 |
| swapon | 打開交換文件和設備 |
| swapoff | 關閉交換文件和設備 |
| bdflush | 控制bdflush守護進程 |
| sysfs | 取核心支持的文件系統類型 |
| sysinfo | 取得系統信息 |
| adjtimex | 調整系統時鐘 |
| alarm | 設置進程的鬧鐘 |
| getitimer | 獲取計時器值 |
| setitimer | 設置計時器值 |
| gettimeofday | 取時間和時區 |
| settimeofday | 設置時間和時區 |
| stime | 設置系統日期和時間 |
| time | 取得系統時間 |
| times | 取進程運行時間 |
| uname | 獲取當前UNIX系統的名稱、版本和主機等信息 |
| vhangup | 掛起當前終端 |
| nfsservctl | 對NFS守護進程進行控制 |
| vm86 | 進入模擬8086模式 |
| create_module | 創建可裝載的模塊項 |
| delete_module | 刪除可裝載的模塊項 |
| init_module | 初始化模塊 |
| query_module | 查詢模塊信息 |
| *get_kernel_syms | 取得核心符號,已被query_module代替 |
回頁首
四、內存管理
| brk | 改變數據段空間的分配 |
| sbrk | 參見brk |
| mlock | 內存頁面加鎖 |
| munlock | 內存頁面解鎖 |
| mlockall | 調用進程所有內存頁面加鎖 |
| munlockall | 調用進程所有內存頁面解鎖 |
| mmap | 映射虛擬內存頁 |
| munmap | 去除內存頁映射 |
| mremap | 重新映射虛擬內存地址 |
| msync | 將映射內存中的數據寫回磁盤 |
| mprotect | 設置內存映像保護 |
| getpagesize | 獲取頁面大小 |
| sync | 將內存緩沖區數據寫回硬盤 |
| cacheflush | 將指定緩沖區中的內容寫回磁盤 |
回頁首
五、網絡管理
| getdomainname | 取域名 |
| setdomainname | 設置域名 |
| gethostid | 獲取主機標識號 |
| sethostid | 設置主機標識號 |
| gethostname | 獲取本主機名稱 |
| sethostname | 設置主機名稱 |
回頁首
六、socket控制
| socketcall | socket系統調用 |
| socket | 建立socket |
| bind | 綁定socket到端口 |
| connect | 連接遠程主機 |
| accept | 響應socket連接請求 |
| send | 通過socket發送信息 |
| sendto | 發送UDP信息 |
| sendmsg | 參見send |
| recv | 通過socket接收信息 |
| recvfrom | 接收UDP信息 |
| recvmsg | 參見recv |
| listen | 監聽socket端口 |
| select | 對多路同步I/O進行輪詢 |
| shutdown | 關閉socket上的連接 |
| getsockname | 取得本地socket名字 |
| getpeername | 獲取通信對方的socket名字 |
| getsockopt | 取端口設置 |
| setsockopt | 設置端口參數 |
| sendfile | 在文件或端口間傳輸數據 |
| socketpair | 創建一對已聯接的無名socket |
回頁首
七、用戶管理
| getuid | 獲取用戶標識號 |
| setuid | 設置用戶標志號 |
| getgid | 獲取組標識號 |
| setgid | 設置組標志號 |
| getegid | 獲取有效組標識號 |
| setegid | 設置有效組標識號 |
| geteuid | 獲取有效用戶標識號 |
| seteuid | 設置有效用戶標識號 |
| setregid | 分別設置真實和有效的的組標識號 |
| setreuid | 分別設置真實和有效的用戶標識號 |
| getresgid | 分別獲取真實的,有效的和保存過的組標識號 |
| setresgid | 分別設置真實的,有效的和保存過的組標識號 |
| getresuid | 分別獲取真實的,有效的和保存過的用戶標識號 |
| setresuid | 分別設置真實的,有效的和保存過的用戶標識號 |
| setfsgid | 設置文件系統檢查時使用的組標識號 |
| setfsuid | 設置文件系統檢查時使用的用戶標識號 |
| getgroups | 獲取后補組標志清單 |
| setgroups | 設置后補組標志清單 |
回頁首
八、進程間通信
| ipc | 進程間通信總控制調用 |
1、信號
| sigaction | 設置對指定信號的處理方法 |
| sigprocmask | 根據參數對信號集中的信號執行阻塞/解除阻塞等操作 |
| sigpending | 為指定的被阻塞信號設置隊列 |
| sigsuspend | 掛起進程等待特定信號 |
| signal | 參見signal |
| kill | 向進程或進程組發信號 |
| *sigblock | 向被阻塞信號掩碼中添加信號,已被sigprocmask代替 |
| *siggetmask | 取得現有阻塞信號掩碼,已被sigprocmask代替 |
| *sigsetmask | 用給定信號掩碼替換現有阻塞信號掩碼,已被sigprocmask代替 |
| *sigmask | 將給定的信號轉化為掩碼,已被sigprocmask代替 |
| *sigpause | 作用同sigsuspend,已被sigsuspend代替 |
| sigvec | 為兼容BSD而設的信號處理函數,作用類似sigaction |
| ssetmask | ANSI C的信號處理函數,作用類似sigaction |
2、消息
| msgctl | 消息控制操作 |
| msgget | 獲取消息隊列 |
| msgsnd | 發消息 |
| msgrcv | 取消息 |
3、管道
| pipe | 創建管道 |
4、信號量
| semctl | 信號量控制 |
| semget | 獲取一組信號量 |
| semop | 信號量操作 |
5、共享內存
| shmctl | 控制共享內存 |
| shmget | 獲取共享內存 |
| shmat | 連接共享內存 |
| shmdt | 拆卸共享內存 |
參考資料
- Linux man pages
- Advanced Programming in the UNIX Environment, W. Richard Stevens, 1993
總結
以上是生活随笔為你收集整理的【Linux系统编程】 Linux系统调用概述的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【电子电路】上拉电阻与下拉电阻有什么作用
- 下一篇: 【Linux系统编程】文件IO操作