系统调用

系统调用是操作系统向应用程序提供的程序接口。用户程序不能直接执行特权指令,也不能直接访问内核数据结构;凡是涉及受保护资源或需要内核权限的操作,都必须通过系统调用请求内核完成。

类型 例子
进程控制 创建进程、终止进程、等待子进程
文件管理 创建、打开、读写、关闭、删除文件
设备管理 请求 I/O、释放设备、获取设备状态
内存管理 申请内存、映射文件、调整地址空间

调用过程

一次系统调用跨越用户态与内核态:

  1. 用户程序按照约定准备系统调用号和参数。
  2. 用户程序执行 trap 指令,也叫陷入指令访管指令
  3. CPU 产生自陷。硬件保存必要现场、切换到内核态,并跳转到统一的系统调用入口。
  4. 系统调用入口检查系统调用号和参数,再分派到对应的内核处理程序。
  5. 内核处理程序执行所请求的服务,将结果或错误码写入约定位置。
  6. 内核执行返回操作,恢复用户程序现场和用户态,用户程序从 trap 后的指令继续运行。

系统调用引发的自陷是程序主动进入内核的同步事件。它与外部设备异步产生的中断不同,但二者都会使 CPU 转入内核态。CPU 状态和切换条件见 CPU-Modes,自陷的分类见 异常

用户程序不能自行修改特权级

trap 指令只负责发出受控请求。真正的状态切换、入口选择和现场保护由硬件按照预设规则完成,用户程序不能指定任意内核入口,也不能直接把 CPU 改为内核态。

# 系统调用与库函数

库函数不等于系统调用。 库函数是程序调用的普通函数接口,是否进入内核取决于其实现:

  • 数学计算、字符串处理等库函数通常完全在用户态执行。
  • 文件创建、进程创建、网络读写等库函数通常封装一个或多个系统调用。
  • 一个库函数可能在用户态完成部分工作,只在必要时进入内核。例如带缓冲的输出函数可以先把数据写入用户态缓冲区,缓冲区需要提交时才调用内核写接口。

因此,调用库函数是语言或运行库层面的函数调用;执行系统调用则意味着通过受控入口请求操作系统服务,并发生用户态到内核态的切换。