系统调用的介绍
一、系统调用的作用
- 提供接口:系统调用是操作系统提供给编程人员的唯一接口,通过它,用户程序可以请求操作系统提供的服务和资源。
- 状态切换:系统调用是使CPU状态从用户态陷入内核态的唯一途径。在用户态下,程序无法直接访问系统硬件和内核资源,而系统调用提供了一个安全、受控的方式来实现这种访问。
二、系统调用的类型
系统调用通常根据其功能被分为以下几类:
- 进程控制类:用于进程创建、终止、等待、替换、进程数据段大小改变及进程标识符或指定进程属性获得等。
- 文件操纵类:用于文件创建、打开、关闭、读/写及文件读写指针移动和属性修改,目录创建及索引结点建立等。
- 进程通信类:用于实现通信机制,如消息传递、共享存储区及信息量集机制等。
- 信息维护类:用于实现日期、时间及系统相关信息设置和获得。
三、系统调用的执行过程
系统调用的执行过程通常包括以下几个步骤:
- 硬件接收信号:当用户程序发起系统调用时,硬件接收到一个特殊的指令(如陷阱指令或中断指令),并立即保存当前执行环境的现场信息。
- 查找中断向量表:硬件查找中断向量表,找到与系统调用对应的入口地址,并将CPU的控制权交给系统调用的总入口程序。
- 保存现场并查找系统调用库:系统调用总入口程序保存当前进程的现场信息,将参数保存在内核的堆栈中,并查找系统调用库以找到对应的系统调用处理程序。
- 执行系统调用处理程序:找到对应的系统调用处理程序后,CPU开始执行该程序,完成用户请求的服务。
- 恢复现场并返回用户程序:系统调用处理程序执行完成后,恢复之前保存的现场信息,并将控制权交还给用户程序,继续执行用户程序的下一条指令。
四、系统调用的实现机制
系统调用的实现机制主要依赖于中断/异常机制和系统调用表。
- 中断/异常机制:系统调用实际上是通过中断/异常机制来实现的。当用户程序发起系统调用时,硬件会产生一个中断信号,并通过中断向量表找到系统调用的入口地址。
- 系统调用表:系统内核内部维护一张全局表(如sys_call_table),表中的每个条目记录着每个系统调用在内核代码中的实现入口地址。当系统调用处理程序被调用时,它会根据系统调用号(即功能号)在系统调用表中找到对应的实现代码入口地址,并执行相应的系统调用。
五、系统调用与库函数的区别
虽然普通应用程序可以直接进行系统调用,但在实际应用中,通常是在应用程序中先加载C函数库或API接口,由这些库或接口去申请系统调用。这是因为系统调用通常比较底层和复杂,直接使用可能会增加编程难度和出错率。而库函数则提供了更高层次、更易于使用的接口来封装系统调用的细节。