1.3 操作系统运行环境

1.3 操作系统运行环境

1. 操作系统的运行机制

1.1 程序是如何运行的?

  • 一条高级语言的代码翻译过来可能会对应多条二进制机器指令
  • 程序运行的过程其实是CPU执行一条一条的机器指令的过程
    • "指令"就是处理机(CPU)能识别、执行的最基本命令

1.2 内核程序 vs 应用程序

  • 应用程序
    • 普通程序员写的程序就是"应用程序"
  • 内核程序
    • 微软、苹果有一帮人负责实现操作系统, 他们写的是"内核程序"
    • 由很多内核程序组成了"操作系统内核", 或简称"内核(Kernel)"
    • 内核是操作系统最重要最核心的部分, 也是最接近硬件的部分, 甚至可以说, 一个操作系统只要有内核就够了(eg: Docker→ 仅需Linux内核)

1.3 特权指令 vs 非特权指令

  • 特权指令
    • 操作系统内核作为"管理者", 有时会让CPU执行一些"特权指令", 如: 内存清零指令, 这些指令影响重大, 只允许"管理者" -- 即操作系统内核来使用
  • 非特权指令
    • 应用程序只能使用"非特权指令", 如: 加法指令、减法指令
    • 在CPU设计和生产的时候就划分了特权指令和非特权指令, 因此CPU执行一条指令前就能判断出其类型

1.4 用户态 vs 内核态

  • CPU有两种状态: "内核态" 和 "用户态"
    • CPU中有一个寄存器叫程序状态字寄存器(PSW), 其中有一个二进制位能够表示CPU为用户态还是内核态
    • 内核态=核心态=管态; 用户态=目态
  • 用户态
    • 处于用户态时, 说明此时正在运行的是应用程序, 此时只能执行非特权指令
  • 核心态
    • 处于核心态时, 说明此时正在运行的是内核程序, 此时可以执行特权指令
  • 两种状态的切换
    • 内核态 → 用户态
      • 执行一条特权指令 -- 修改PSW的标志位为"用户态", 这个动作意味着操作系统将主动让出CPU特权
    • 用户态 → 内核态
      • 由"中断"引发, 硬件自动完成变态过程, 触发中断信号意味着操作系统将强行夺回CPU的使用权
      • 除了非法使用特权指令之外, 还有很多事件会触发中断信号。一个共性是: 但凡需要操作系统介入的地方, 都会触发中断信号
    • 示例:
      1. 刚开机时, CPU为"内核态", 操作系统内核程序先上CPU运行
      2. 开机完成后, 用户可以启动某个应用程序
      3. 操作系统内核程序在合适的时候主动让出CPU, 让该应用程序上CPU运行
        • 操作系统内核在让出CPU之前, 会用一条特权指令把PSW的标志位设置为"用户态"
      4. 应用程序运行在"用户态"
      5. 此时黑客在应用程序中植入了一条特权指令, 企图破坏系统
      6. CPU发现接下来要执行的这条指令是特权指令, 但是自己又处于"用户态"
      7. 这个非法事件会引发一个中断信号
        • CPU检测到中断信号后, 会立即变为"内核态", 并停止运行当前的应用程序, 转而运行处理中断信号的内核程序
      8. "中断"使操作系统再次夺回CPU的控制权
      9. 操作系统会对引发中断的事件进行处理, 处理完了再把CPU使用权交给应用程序

2. 中断和异常

  • 中断”是让操作系统内核夺回CPU使用权的唯一途径

2.1 内中断(异常)

  • 与当前执行的指令有关,中断信号来源于CPU内部
  • 示例:
    1. 试图在用户态下执行特权指令
    2. 执行除法指令时发现除数为 0
      • 若当前执行的指令是非法的,则会引发一个中断信号
    3. 有时候应用程序想请求操作系统内核的服务,此时会执行一条特殊的指令 -- 陷入指令
      • (访管指令),该指令会引发一个内部中断信号
      • 执行“陷入指令”,意味着应用程序主动地将CPU控制权还给操作系统内核
      • 系统调用”就是通过陷入指令完成的
  • 分类:
    • 陷阱、陷入(trap)
      • 由陷入指令引发,是应用程序故意引发的
    • 故障(fault)
      • 由错误条件引起的,可能被内核程序修复
      • 内核程序修复故障后会把CPU使用权还给应用程序,让它继续执行下去
      • 如:缺页故障(缺页中断)
    • 终止(abort)
      • 由致命错误引起,内核程序无法修复该错误
      • 因此一般不再将CPU使用权还给引发终止的应用程序,而是直接终止该应用程序
      • 如: 整数除0、非法使用特权指令

2.2 外中断(中断)

  • 与当前执行的指令无关,中断信号来源于CPU外部
  • 每一条指令执行结束时,CPU都会例行检查是否有外中断信号
  • 示例:
    • 时钟中断 -- 由时钟部件发来的中断信号
      • 时钟部件每隔一个时间片(如 50ms)会给CPU发送一个时钟中断信号
    • I/O中断 -- 由输入/输出设备发来的中断信号
      • 如打印机打印完成后, 向CPU发送中断信号, CPU根据中断信号执行对应的中断处理程序
  • 注意
    • 大多数的教材、试卷中,“中断”特指狭义的中断,即外中断。而内中断一般称为“异常
  • 中断机制的基本原理
    • 不同的中断信号,需要用不同的中断处理程序来处理
    • 当CPU检测到中断信号后,会根据中断信号的类型去查询“中断向量表”,以此来找到相应的中断处理程序在内存中的存放位置

3. 系统调用

3.1 什么是系统调用?

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

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

3.2 系统调用与库函数的区别

普通应用程序 可直接进行系统调用,也可使用库函数。有的库函数涉及系统调用,有的不涉及
编程语言 向上提供库函数。有时会将系统调用封装成库函数,以隐藏系统调用的一些细节,使程序员编程更加方便
操作系统 向上提供系统调用,使得上层程序能请求内核的服务
裸机
  • 不涉及系统调用的库函数:如的“取绝对值”的函数

  • 涉及系统调用的库函数:如“创建一个新文件”的函数

  • 总之,部分库函数是对系统调用的进一步封装,应用程序可以使用库函数进行间接系统调用,也可以进行直接系统调用

3.3 为什么系统调用是必须的?

  • 生活场景:
    • 去学校打印店打印论文,你按下了 WPS 的“打印”选项,打印机开始工作。 你的论文打印到一半时,另一位同学按下了 Word 的“打印”按钮,开始打印他自己的论文。
  • 思考:
    • 如果两个进程可以随意地、并发地共享打印机资源(同时共享),会发生什么情况?
      • 两个进程并发运行,打印机设备交替地收到 WPS 和 Word 两个进程发来的打印请求,结果两篇论文的内容混杂在一起了
  • 解决方法:
    • 由操作系统内核对共享资源进行统一的管理,并向上提供 “系统调用” ,用户进程想要使用打印机这种共享资源,只能通过系统调用向操作系统内核发出请求,以此来实现不同的进程对打印机资源的互斥共享,内核会对各个请求进行协调处理

3.4 什么功能要用系统调用实现?

  • 应用程序通过系统调用请求操作系统的服务。而系统中的各种共享资源都由操作系统内核统一掌管,因此凡是与共享资源有关的操作(如存储分配、I/O操作、文件管理等),都必须通过系统调用的方式向操作系统内核提出服务请求,由操作系统内核代为完成。这样可以保证系统的稳定性和安全性,防止用户进行非法操作

  • 功能分类(了解即可):

    • 设备控制: 完成设备的 请求/释放/启动 等功能
    • 文件管理: 完成文件的 读/写/创建/删除 等功能
    • 进程控制: 完成进程的 创建/撤销/阻塞/唤醒 等功能
    • 进程通信: 完成进程之间的 消息传递/信号传递 等功能
    • 内存管理: 完成内存的 分配/回收 等功能

3.5 系统调用的过程

  • 传递系统调用参数(将系统调用需要的参数放到某些通用寄存器中) → 执行陷入指令(用户态)→ 执行相应的内核程序(根据寄存器中的参数判断用户需要哪种系统调用服务)处理系统调用(核心态)→ 返回应用程序

  • 注意:

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

1.3 操作系统运行环境
http://binbo-zappy.github.io/2024/11/19/操作系统/1-3-操作系统运行环境/
作者
Binbo
发布于
2024年11月19日
许可协议