System Calls
系统调用
系统调用是操作系统向应用程序提供的程序接口。用户程序不能直接执行特权指令,也不能直接访问内核数据结构;凡是涉及受保护资源或需要内核权限的操作,都必须通过系统调用请求内核完成。
| 类型 | 例子 |
|---|---|
| 进程控制 | 创建进程、终止进程、等待子进程 |
| 文件管理 | 创建、打开、读写、关闭、删除文件 |
| 设备管理 | 请求 I/O、释放设备、获取设备状态 |
| 内存管理 | 申请内存、映射文件、调整地址空间 |
调用过程
一次系统调用跨越用户态与内核态:
- 用户程序按照约定准备系统调用号和参数。
- 用户程序执行 trap 指令,也叫陷入指令或访管指令。
- CPU 产生自陷。硬件保存必要现场、切换到内核态,并跳转到统一的系统调用入口。
- 系统调用入口检查系统调用号和参数,再分派到对应的内核处理程序。
- 内核处理程序执行所请求的服务,将结果或错误码写入约定位置。
- 内核执行返回操作,恢复用户程序现场和用户态,用户程序从 trap 后的指令继续运行。
系统调用引发的自陷是程序主动进入内核的同步事件。它与外部设备异步产生的中断不同,但二者都会使 CPU 转入内核态。CPU 状态和切换条件见 CPU-Modes,自陷的分类见 异常。
用户程序不能自行修改特权级
trap 指令只负责发出受控请求。真正的状态切换、入口选择和现场保护由硬件按照预设规则完成,用户程序不能指定任意内核入口,也不能直接把 CPU 改为内核态。
库函数不等于系统调用。 库函数是程序调用的普通函数接口,是否进入内核取决于其实现:
- 数学计算、字符串处理等库函数通常完全在用户态执行。
- 文件创建、进程创建、网络读写等库函数通常封装一个或多个系统调用。
- 一个库函数可能在用户态完成部分工作,只在必要时进入内核。例如带缓冲的输出函数可以先把数据写入用户态缓冲区,缓冲区需要提交时才调用内核写接口。
因此,调用库函数是语言或运行库层面的函数调用;执行系统调用则意味着通过受控入口请求操作系统服务,并发生用户态到内核态的切换。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Elian's blog page!