前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >“系统调用”究竟是不是个函数?

“系统调用”究竟是不是个函数?

原创
作者头像
程序饲养员
发布2023-12-29 16:21:48
1800
发布2023-12-29 16:21:48
举报
文章被收录于专栏:风骚语言Rust风骚语言Rust

老规矩,如果能回答上这些问题,就没必要看这篇文章了,做些更有意义的事情吧。

  • 系统调用和普通函数有何区别?
  • 什么是内核态用户态
  • 操作系统如何让CPU切换状态?
  • 内中断、外中断、软中断、硬中断是什么意思?
  • 库函数和系统调用有何区别?
代码语言:c
复制
#include <fcntl.h>
int open(const char *path, int oflag, .../* mode_t mode */)

这是一个系统调用,看起来跟我们写的C函数签名一模一样,由此可以得出结论,系统调用就是一个函数。

这个结论是不是有点肤浅,哈哈。我们来看看这个结论是否靠谱。

这个“函数”与我们写的函数有什么差异呢?

主要差异就体现在系统调用过程中CPU发生了由用户态->内核态->用户态的状态转换,而我们应用程序写的函数自始至终都是用户态运行。

下面我们就来解密这个过程。

“内核态” 和 “用户态”

在CPU设计生产时就划分了特权指令和非特权指令,因此CPU执行一条指令前就能判断出其类型。

一些危险指令只能由操作系统来执行,例如清空内存指令,如果让某个用户程序执行那么会影响整个系统。所以CPU需要一种机制来避免这种事情发生,因此划分了这两种状态:内核态、用户态。

CPU 中有个寄存器叫 程序状态字寄存器(PSW),其中有二进制位1表示“内核态”、0表示“用户态”(有些CPU可能相反)。

  1. 处于内核态时,说明此时正在运行的是内核程序,此时可以执行特权指令
  2. 处于用户态时,说明此时正在运行的是用户程序,此时只能执行非特权指令

别名: 内核态=核心态=管态;

用户态=目态

操作系统如何让CPU切换状态?

我们通过一个案例来说明CPU切换状态的几种情况。

电脑开机后,CPU处于内核态。需要启动应用程序时,操作系统会主动出让CPU,让应用程序在CPU上执行。在出让CPU前先执行一条特权指令把PSW置为用户态,之后应用程序就能正常执行了。假如有黑客让应用程序中包含一条只有在CPU内核态才能运行的特权指令,就会触发中断(由CPU自己发出中断信号),此时操作系统收到中断信号接管CPU,开始执行操作系统内核的中断处理程序(这种情况中断程序通常会直接kill用户进程)。

总结一下这个案例中的状态切换:

  1. 内核态 --> 用户态:执行一条特权指令把PSW置为用户态
  2. 用户态 --> 内核态:用户态执行特权指令引发中断,导致PSW置为内核态

引发状态切换的有特权指令和中断,特权指令我们知道是CPU的一些危险指令集,那中断是什么呢?

中断和异常

1. 内中断(也称为”异常“或软中断)

与CPU当前执行的指令有关,中断信号来源于CPU内部。

例如,

  1. 应用程序内非法执行一条特权指令,CPU正处于用户态(不允许执行特权指令),便会触发内中断。
  2. 正常指令也会导致内中断,如除法指令遇到除数为零。
  3. 还有一种情况是应用程序需要请求操作系统内核的服务,此时会执行一条特殊的指令陷入指令(也称为“trap指令”或“访管指令”),陷入指令是一个普通指令,并不是特权指令系统调用就是陷入指令实现的。
2. 外中断(也称为硬中断)

与CPU当前执行的指令无关,中断信号来源于CPU外部。

CPU在执行完每条指令后,都会例行检查有没有外中断信号。

例如,

  1. 时钟中断,由时钟部件发出来的中断信号,当CPU检测到有中断信号时,会暂停正在运行的用户程序,转而执行时钟中断的内核程序,这段程序一般就是进程调度程序。并发就是基于此实现的。
  2. IO中断,例如打印机完成打印任务后,触发IO中断信号,CPU就会执行操作系统内核的IO中断处理程序。

无论是内中断还是外中断,让操作系统夺回CPU使用权的唯一途径是”中断“,使CPU由用户态转变为内核态。如果没有中断机制,就无法切回内核程序,进程调度无法执行也就没有并发技术了。

下面的图总结了中断的几种情况:

3. 中断机制的基本原理

如图不同的中断信号,需要用不同的中断处理程序来处理。 当CPU检测到中断信号后,会根据中断信号的类型去查询“中断向量表”,以此来找到相应的中断处理程序在内存中的存放位置。

铺垫完这部分知识,说回系统调用。

现在我们就明白了之前讨论的,当发生系统调用时CPU由用户态->内核态->用户态的状态转换的原理。

我们拆成两个步骤来介绍进程系统调用的细节:

  1. 用户态->内核态 当函数执行系统调用时,首先执行传参指令将程序参数放到CPU寄存器上,例如系统调用的类型(如fork)以及其他参数。CPU陷入指令会导致中断,因此内核接管CPU。那么此时执行这个函数的进程就被阻塞了,紧接着CPU根据中断向量表执行中断处理程序,发现是系统调用就执行这个系统调用相关的代码指令。
  2. 内核态->用户态 执行完系统调用相关的代码指令,将结果写入内存地址,以备进程恢复后读取结果。再之后执行特权指令把CPU设置为用户态,进程恢复读取系统调用的结果继续执行函数内其它指令。

总结一下:

应用程序可以通过系统调用来请求获得操作系统内核的服务,Java程序员可以理解为操作系统提供的API。

库函数的执行过程与我们自己写的函数并无不同,它们是由标准组织定义实现,方便开发者使用。但是因为库函数需要考虑各种边界情况,实际性能未必有我们自己实现的性能好,所以不要盲目认为库函数性能一定很强。对于Java程序员可以对标 Java标准库 理解。

下面这个图能更直观的表现出库函数、系统调用、用户程序之间的关系:

如下图就是操作系统提供的各种共享资源 ,用户进程想要使用共享资源,只能通过系统调用向操作系统内核发出请求。内核会对各个请求进行协调处理,这样可以保证系统的稳定性和安全性,防止用户进行非法操作。

这篇文章是学习《王道考研》的操作系统课整理而来。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • “内核态” 和 “用户态”
    • 操作系统如何让CPU切换状态?
      • 中断和异常
        • 1. 内中断(也称为”异常“或软中断)
        • 2. 外中断(也称为硬中断)
        • 3. 中断机制的基本原理
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档