《操作系统 - 清华大学》2 -2:中断、异常和系统调用

文章目录

  • 1. 中断和异常处理机制
    • 1.1 中断
    • 1.2 异常
  • 2. 系统调用
    • 2.1 标志C库的例子
    • 2.2 编程接口
  • 3.系统调用的实现
  • 4. 程序调用和系统调用的不同处
  • 5. 中断、异常和系统调用的开销

1. 中断和异常处理机制

接下来看一看中断和异常的处理过程,看下图就比较清楚,中断和异常都有硬件的处理过程和软件的处理过程,合在一起才能够正确地完成中断和异常的操作系统服务。

在这里插入图片描述
关注上图,可以看出,

  1. 首先产生中断或者异常之后,它需要知道具体这个中断或者异常异应该是由哪个特定的服务例程来服务。这一点是需要判断的,为此需要建立好一个表,表的一侧是中断号或者是异常号,因为一旦每个中断和异常把它编号之后,就很容易区分出来,到底产生的是硬盘的中断,还是键盘的中断,还是鼠标的中断,这很容易区分出来,不同的外设产生的中断,具有一个特定的编号。
  2. 有编号后,特定的编号就有一个对应的地址,这个地址实际上就是针对这个特定中断的服务例程的地址。有这个地址后,就可以假定,操作系统收到这个中断之后,就可以直接查这个中断表,查到它对应的中断服务例程的那个起始地址,直接转跳到那去执行就 OK 了。

这实际是简单的描述,但为能够让整个系统能够正常地工作,还需要去完成一些更多的事情。

1.1 中断

当产生中断之后,是打断了当前的正常执行,来处理一个更加紧急的外设中断事件。那打断了程序正常执行的话,就需要在硬件和软件方面做出一定的保护,称之为保存恢复机制,有保存恢复才能够让操作系统在完成中断处理之后,能够正常地继续运行。这是中断处理过程中需要注意的具体实现细节。它分两部分来完成:

  1. 第一部分硬件,首先外设是一个硬件,当它需要让操作系统产生相应的支持之后,那需要产生一个标记,让 CPU 知道,外设产生一个中断标记,CPU 看到这个标记之后,它会得出到底是哪一号中断,为此会产生一个具体的中断号,然后把这个中断号发给操作系统,从而操作系统可以根据中断号找到对应的处理例程,这是硬件要完成的事情。

  2. 那软件呢?软件就是操作系统,它具体完成什么事情呢?
    在这里插入图片描述

  • 首先,操作系统需要保存被打断的执行现场。

什么叫被打断的执行现场?程序正在执行过程中,突然产生了中断,那首先需要把被打断的这个程序当前执行的一些状态给保证起来,比如它执行什么地方,它执行的寄存器的内容是什么,这些都要保证起来,便于后续恢复,能够让程序从被打断的点继续往下执行,这是操作系统来完成的,保存当前被打断程序的执行的现场。

  • 再者,保存完之后,根据 CPU 给的这个中断号,查到对应的中断处理例程的地址,然后跳去执行,那这个过程中,会根据这个外设产生中断的具体情况来完成相应操作。

比如是网卡外设,来了个数据包,中断服务例程就需要把这个数据包取出来做进一步处理,这是中断服务例程要干的事情。

  • 接下来,当中断服务例程处理完之后,应该让当前被打断的程序去继续执行,这就需要去恢复刚才保存好的数据,把它恢复回去,从而使应用程序在完全不知情的情况下继续它的执行过程。

这也是为什么中断整个执行过程其实是对应用程序透明的,应用程序完全可以不用感知到有中断产生,这是中断的处理过程。

1.2 异常

异常和中断不太一样

  • 异常也是当应用程序执行特定指令之后,这条特定指令触发了一个异常事件,比如除零操作,触发这个异常事件,那么它也会有一个异常的编号。

  • CPU 会得到异常的 ID 号,根据这个 ID 号,操作系统需要保存产生异常的现场,产生异常这条指令的地址以及当前一些寄存器的内容,保存完之后,操作系统根据这个异常的编号去做相应的处理。

  • 如果说处理过程是决定这个应用程序退出执行,操作系统就会把这个程序给杀死,让它不在继续执行,这是一种情况。另一种情况也有可能是说,操作系统认为这个程序产生异常是由于操作系统服务不到位,服务应该把产生异常这个现象给弥补好,让程序可以继续执行,这种情况下,操作系统要完成相应的弥补工作,弥补完之后,根据刚才异常产生的现场进行恢复保存的那些值,寄存器保存的地址恢复之后,让应用程序重新执行。

    需要注意,这一点和前面的中断和系统调用不一样,是重新执行那条指令,那么这时候在重新执行过程中,由于操作系统已经把产生异常的原因给修补好了。所以应用程序再次执行这条指令就不会再产生异常了,那也意味着程序可以继续地往下执行。

其实在这过程中,它也是对应用程序透明的,应用程序其实根本不知道在执行到某个特定指令时会产生异常,这一点是和刚才中断处理过程是类似的。那这是中断和异常整个处理过程的简要描述。

2. 系统调用

系统调用和中断异常不太一样,系统调用是来源于应用程序需要操作系统提供服务,而服务不能由应用程序直接来执行,必须要操作系统来执行,那么这个过程就需要有一个接口,这个接口称为系统调用接口,那么有这个接口之后,就可以让操作系统来给应用程序提供各种各样的服务。

2.1 标志C库的例子

举个例子,下图可以看到:
在这里插入图片描述

应用程序很简单,它是简单的 C 程序,有一条指令叫 printf 打印一个字符串,打印在屏幕上,printf 是一条指令,最终会触发一条系统调用。

触发 write 系统调用,write 会带一些参数,参数包含要让哪个设备来显示这个字符串,以及字符串的内容,很明显需要这两个参数,然后操作系统在获取这个参数之后,去直接访问对应的设备,比如说屏幕,让屏幕把这个字符串给显示出来。

整个处理过程是操作系统来完成,不是应用程序来完成,应用程序只需发出这个请求就 OK 了,当操作系统完成这个请求之后,就会返回一个成功或者失败,当操作系统做完这个处理之后,应用程序能够继续后续的执行工作。

这是一个简单的一个例子,对于其他那些系统调用而言也是大致的同样的处理过程,只是具体完成内容不一样而已。那上图右边这个图可以看出来是一个通用的系统调用接口,有这层接口,应用程序就可以完成各种各样功能,来对整个计算机系统进行间接的控制和管理。

2.2 编程接口

在这里插入图片描述

  • 为了方便应用程序能够使用操作系统的系统调用接口,有很多定义好的 API,比如用 C 语言或者 C++语言定了很多 API,比如 windows 系统专门有一个 Windows 32的 API,提供这个 API 之后, Windows 应用程序可以用这个 API 来访问 Windows 提供的各种各样的服务。

  • 那对我们 UNIX 而言,比如说 Linux,还有其他一些 UNIX 的操作系统,那么它们会有一个标准的 POSIX 的 API,POSIX 意思就是通用可移植的系统调用接口标准,这个标准它会让写好应用程序在只要遵循这个标准的操作系统里可以执行,这样可以实现很好的跨平台的好处,那这是 UNIX 系统里面常见的一种系统调用的API 接口。

  • Java 也提供了很多 API,那些 API 是不是系统调用呢?其实那些 API 不是,那些 API 只是 Java 的虚拟机提供的一些支持,它由库来实现的,最终还是会通过类似于跑在 Windows 环境下 win 32的 API,如果跑在Linux 环境下,会用 POSIX API 来实现相应服务。

    那这点是需要注意层次概念,最底层就是一个 WIN32 或者 POSIX API,它定义了操作系统到底能提供哪些系统调用,有不同系统调用之后,还需要了解什么呢?

3.系统调用的实现

既然学习操系统,就有必要去了解操系统怎么去完成这个系统调用
在这里插入图片描述

前面讲到它有 interface,应用程序会直接或者是间接地通过库来访问这个系统调用的接口。一旦访问系统调用接口之后,会触发从用户态到内核态的转换。

什么叫用户态?什么叫内核态?
  ~  
用户态是指应用程序在执行的过程中 CPU 所处于执行特权级的状态,特权级特别低,不能够直接访问某些特殊的机器指令和 IO。
  ~  
内核态是指操作系统运行过程中 CPU 所处于状态,在这个状态下,操作系统可以执行任何一条指令,包括特权指令,包括访问 IO 指令,这使得安全性可以得到保障,当然应用程序处于用户态的时候,它无法执行这些特权指令和 IO 指令,它无法完全地控制整个计算机系统。

当操作系统处于内核态的时候,它其实是可以完全控制整个计算机系统,这点是不一样的。

那有了系统调用接口之后,操作系统需要完成一个特殊的转化,就是说当应用程序调用系统调用的时候,会完成从用户态到内核态转换,从而使得控制权从应用程序交到了操作系统来,那么操作系统可以对应用程序发出这些系统调用的参数,系统调用的 ID 号做出标识,做标识之后,就可以被识别,然后完成具体的服务,这是它的处理过程。

4. 程序调用和系统调用的不同处

需要了解到这里面除了特权级转换之外,还需要有一些新的变化,主要是区别说系统调用和传统函数调用有区别的,区别在哪?
在这里插入图片描述

  1. 当应用程序发出函数调用的时候,它其实是在一个栈空间,在一个栈空间完成了参数的传递和参数的返回。

  2. 但是在系统调用的执行过程中,应用程序和操作系统实际上是拥有各自的堆栈,也就意味着当应用程序发出系统调用之后,当切换到内核里去执行的时候,需要去切换堆栈。同时还需要去完成特权级的转换,从用户态到内核态的转换。

    那么这个转换和这个堆栈的切换都会需要一定的开销,也意味着当执行系统调用的时候,那么它带来的开销会比执行函数调用要大很多。 当然这个开销是有它相应的回报,这回报就是安全可靠,这是操作系统为此不得不付出时间上的代价。

系统调用、中断和异常在操系统、应用程序和外设的大致交互过程。这个过程可以看到,它其实跨越操作系统的边界,系统调用、异常和 中断这三者是跨越了操作系统和应用程序,操作系统和外设的边界,跨越边界其实是有一定的代价,这个代价是为了确保让操作系统能够安全可靠、正常的运行,那到底是哪些代价呢?

5. 中断、异常和系统调用的开销

在这里插入图片描述

  1. 操作系统要能够对产生不同的异常、中断和系统调用正常地进行处理,那首先需要有一个对应的映射关系,就是说对应具体的系统调用号,对应具体的中断号,那么它应该由哪个中断例程或者系统调用例程来处理,那么这个映射的表,操作系统在初始的环节就需要把表建好。

  2. 操作系统有自己的堆栈,不能和应用程序堆栈混为一谈,那这样的话就使得要维护堆栈的开销,需要知道操作系统退出时候需要把这堆栈保存,操作系统执行的时候要把堆栈恢复,同理也是一样,应用程序在退出执行到内核里面来执行之后,需要把应用程序的堆栈做保存,以及最后会做恢复的处理过程。

  3. 同时操作系统不信任应用程序,它可能会认为应用程序会有恶意的情况存在,所以说它在收到应用程序发出的请求之后,会对参数做检查。这个检查也是需要一定的时间开销,那这个开销主要是安全上的时间开销。

  4. 操作系统处理完某些数据之后,需要把这个数据从内核态传到用户态,就所谓的拷贝过程,那内存拷贝会有新的开销,它不像应用程序可以简单地使用指针传递的方式来实现。它必须要把内存空间的数据从内核空间拷贝到用户空间,这是拷贝开销。

  5. 以及随着应用程序的执行,有可能会引起内存状态的改变,这是后续会讲到,所谓页机制的转变。关于 CPU 的 cacheTLB 有可能会被刷新,刷新过程会导致额外的开销。

这些都是在执行中断、异常和系统调用上可能会带来的开销,但是大家要注意这些开销是值得的,也是必须的,因为这些开销的存在来使得操作系统能够保证是在安全可靠的环境中执行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/912424.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Nginx简易配置将内网网站ssh转发到外网

声明:本内容仅供交流学习使用,部署网站上线还需要根据有关规定申请域名以及备案。 背景 在内网的服务器有一个运行的网页,现使用ssh反向代理,将它转发到外网的服务器。 但是外网的访问ip会被ssh反向代理拦截 所以使用Nginx进行…

Moment.js、Day.js、Miment,日期时间库怎么选?

一直以来,处理时间和日期的JavaScript库,选用的都是Momment.js。它的API清晰简单,使用方便灵巧,功能还特别齐全。 大师兄是Moment.js的重度使用者。凡是遇到时间和日期的操作,就把Moment.js引用上。 直到有天我发现加…

后台管理系统窗体程序:文章管理 > 文章发表

目录 文章列表的的功能介绍: 1、进入页面 2、页面内的各种功能设计 (1)进入选择 (2)当获取到唯一标识符时 (3)当没有标识符时 (4)发布按钮,存为草稿 一、网…

Linux服务控制及系统基本加固

一. liunx操作系统的开机引导的过程 1. 开机自检 根据bios的设置,对cpu,内存,显卡,键盘等等设备进行初步检测如果以上检测设备工作正常,系统会把控制权移交到硬盘 总结:检测出包含系统启动操作系统的设备,硬盘&#…

通过 SSH 隧道将本地端口转发到远程主机

由于服务器防火墙,只开放了22端口,想要通过5901访问服务器上的远程桌面,可以通过下面的方式进行隧道转发。 一、示例命令 这条代码的作用是通过 SSH 创建一个 本地端口转发,将你本地的端口(5901)通过加密的 SSH 隧道连接到远程服务器上的端口(5901)。这种方式通常用于在…

WPF+MVVM案例实战与特效(二十八)- 自定义WPF ComboBox样式:打造个性化下拉菜单

文章目录 1. 引言案例效果3. ComboBox 基础4. 自定义 ComboBox 样式4.1 定义 ComboBox 样式4.2 定义 ComboBoxItem 样式4.3 定义 ToggleButton 样式4.4 定义 Popup 样式5. 示例代码6. 结论1. 引言 在WPF应用程序中,ComboBox控件是一个常用的输入控件,用于从多个选项中选择一…

C#中日期和时间的处理

目录 前言 时间对于我们的作用 一些关于时间的名词说明 格里高利历 格林尼治时间(GMT) 协调世界时(UTC) 时间戳 DateTime 初始化 获取时间 计算时间 字符串转DateTime 存储时间 TimeSpan 初始化它来代表时间间隔 用它相互计算 自带常量方便用于和ticks进行计…

pdb和gdb的双剑合璧,在python中调试c代码

左手编程,右手年华。大家好,我是一点,关注我,带你走入编程的世界。 公众号:一点sir,关注领取python编程资料 问题背景 正常情况下,调试python代码用pdb,调试c代码用gdb,…

【Apache ECharts】<农作物病害发生防治面积>

在vs Code里打开, 实现 1. 首先引入 echarts.min.js 资源 2. 在body部分设一个 div,设置 id 为 main 3. 设置 script 3.1 基于准备好的dom,初始化echarts实例 var myChart echarts.init(document.getElementById(main)); 3.2 指定图表的…

Docker + Jenkins + gitee 实现CICD环境搭建

目录 前言 关于Jenkins 安装Jenkins docker中运行Jenkins注意事项 通过容器中的Jenkins,把服务打包到docker进行部署 启动Jenkins 创建第一个任务 前言 CI/CD(持续集成和持续交付/持续部署),它可以实现自动化的构建、测试和部署…

Leetcode 买卖股票的最佳时机 Ⅱ

使用贪心算法来解决此问题,通过在价格上涨的每一天买入并在第二天卖出的方式,累计所有上涨的利润,以实现最大收益。关键点是从第二天开始遍历,并且只要当前比前一天价格高,我们就在前一天买入然后第二天卖出去。下面是…

【Linux系列】命令行中的文本处理:从中划线到下划线与大写转换

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

使用Docker快速部署FastAPI Web应用

Docker是基于 Linux 内核的cgroup、namespace以及 AUFS 类的Union FS 等技术,对进程进行封装隔离,一种操作系统层面的虚拟化技术。Docker中每个容器都基于镜像Image运行,镜像是容器的只读模板,容器是模板的一个实例。镜像是分层结…

【go从零单排】迭代器(Iterators)

🌈Don’t worry , just coding! 内耗与overthinking只会削弱你的精力,虚度你的光阴,每天迈出一小步,回头时发现已经走了很远。 📗概念 在 Go 语言中,迭代器的实现通常不是通过语言内置的迭代器类型&#x…

C语言--结构体的大小与内存对齐,位段详解

一.前言 为了保证文章的质量和长度,小编将会分两篇介绍,思维导图如下,上篇已经讲过了概念部分,本文主要讲解剩余部分,希望大家有所收获🌹🌹 二.结构体的大小与内存对齐 2.1 存在对齐的原因 平…

UnicodeDecodeError: ‘utf-8‘ codec can‘t decode bytes ... - python 报错解决方案

背景 加载数据集突然出问题, 详细报错为:UnicodeDecodeError: utf-8 codec cant decode bytes in position 606-607: invalid continuation byte 解决方案 源文件另存 UTF-8 版的 csv。 即可运行:

MQTT协议解析 : 物联网领域的最佳选择

1. MQTT协议概述 1.1 MQTT协议是什么 MQTT : Message Queuing Telemetry Transport 模式 : 发布 / 订阅主题优点 : 代码量小、低带宽、实时可靠应用 : 物联网、小型设备、移动应用MQTT 常用端口 : 1883 MQTT是一个网络协议,和HTTP类似,因为轻量简单&…

快速入门Zookeeper

Zookeeper ZooKeeper作为一个强大的开源分布式协调服务,扮演着分布式系统中至关重要的角色。它提供了一个中心化的服务,用于维护配置信息、命名、提供分布式同步以及提供组服务等。通过其高性能和可靠的特性,ZooKeeper能够确保在复杂的分布式…

「Mac玩转仓颉内测版1」入门篇1 - Cangjie环境的搭建

本篇详细介绍在Mac系统上快速搭建Cangjie开发环境的步骤,涵盖VSCode的下载与安装、Cangjie插件的离线安装、工具链的配置及验证。通过这些步骤,确保开发环境配置完成,为Cangjie项目开发提供稳定的基础支持。 关键词 Cangjie开发环境搭建VSC…

从0开始学习机器学习--Day20--优化算法的思路

确定执行的优先级(Prioritizing what to work on : Spam classification example) 在建立学习系统前,我们不仅要梳理框架,更重要的是我们要弄清楚有哪些事情是要优先做的,这可以帮我们节约大量的时间。 以垃圾邮件为例,按照之前…