系统调用

概念

操作系统作为用户和计算机硬件之间的接口,需要向上提供一些简单易用的服务。主要命令接口和程序接口。其中程序接口由一组系统调用组成。

alt text

系统调用是操作系统提供给应用程序(程序员/编程人员)使用的接口,可以理解为一种可供应用程序调用的特殊函数,应用程序可以通过系统调用来请求获得操作系统内核的服务

系统调用和库函数的区别

以C语言编写的应用程序为例,该应用程序调用了C语言的库函数,C语言的库函数则是对操作系统提供的系统调用做了一步封装。本质上还是通过系统调用控制计算机的硬件(显示屏等)

当然,并不是所有的C库函数都设计系统调用:

  • 取绝对值函数不涉及系统调用。
  • 创建一个新文件涉及系统调用

为什么系统调用时必须的?

如果两个进程可以随意的,并发的共享打印机资源,会出现什么情况?

比如有两个进程并发的执行,打印机设备交替的接受到了WPS和Word两个进程发来的打印请求。结果就会导致两篇论文就混在一起了。

解决方法:由操作系统的系统调用对共享资源进行统一管理,并向上提供系统调用,用户进程如果想要使用打印机这种共享资源,就只能通过系统调用向操作系统内核发出打印请求。内核回答各个请求协调处理。

什么功能会用到系统调用?

应用程序通过系统调用请求操作系统的服务。而系统中的各种共享资源都由操作系统内核统一掌管,因此凡是与共享资源有关的操作(如存储分配、I/O操作、文件管理等),都必须通过系统调用的方式向操作系统内核提出服务请求,由操作系统内核代为完成。

alt text

系统调用过程

例子:用户在C语言程序中调用了C语言库write()read()函数。

  1. 用户程序发起系统调用​
    • 用户先将该程序编译,生成.exe可执行文件。并运行此文件。
    • CPU读取文件中的二进制指令开始一行一行的执行。参数通过寄存器(如ebx、ecx、edx等)传递给内核。并将系统调用号存入eax寄存器。
  2. 触发中断
    • 传统方式使用int 0x80指令触发中断(x86架构)。
    • 现代CPU通过syscall/sysenter指令直接进入内核态,减少性能损耗。
  3. 中断处理
    • CPU检测到中断后,从用户态切换到内核态,并跳转到预定义的中断向量表中的system_call函数入口。
    • 保存中断现场。
  4. 内核执行系统调用
    • 根据eax中的系统调用号,在系统调用表中索引对应的内核函数地址(如sys_read)。
    • 将存在寄存器的参数拿出来,执行系统调用程序。
  5. 返回用户态​
    • ​​保存返回值​​:内核将结果(如读取的字节数)存入eax寄存器。
    • 恢复中断上下文。
    • CPU执行指令将内核态切换为用户态,继续执行应用程序。

alt text

大致过程:

  1. 传递系统调用参数
  2. 执行陷入指令触发中断(用户态)
  3. 通过终端将用户态变为内核态。
  4. 执行相应的内核程序处理系统调用(内核态)
  5. 返回应用程序。

注意:

  1. 陷入指令是在用户态执行的,执行陷入指令之后立即引发一个内中断,使CPU进入核心态
  2. 发出系统调用请求是在用户态,而对系统调用的相应处理在核心态下进行。