48

Exceptional_Control_Flow

 5 years ago
source link: https://github.com/Dracarys/Articles/blob/master/Exceptional_Control_Flow.md?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

【笔记】ECF Exceptional Control Flow

该文章是《深入理解计算机系统》中第八章关于 ECF 的读书笔记,有大量的原文摘抄,所以本篇文章不在仓库的许可协议之内。如您想了解相关知识请积极购买正版。

ECF

实际上就是一种反馈机制,因为处理一系列事件,并不能始终是按照预定计划进行的,当意料之外的事件发生时,如何处理呢?如何将意外事件反馈给决策者呢?这就是需要意外处理,即本章要介绍的 ECF

当子进程终止时,创建这些子进程的父进程必须得到通知。( 为什么要通知父进程呢?他们不应该是相互独立的吗?

为什么要理解 ECF :

  • 有助于理解操作系统概念:ECF 是操作系统用来实现 I/O、进程和虚拟内存的基本机制;
  • 有助于理解应用程序与操作系统的交互:应用程序通过将使用一个叫做陷阱(trap)或者系统调用(system call)的 ECF形式,想操作系统请求服务。例如:向磁盘写数据、从网络读取数据、创建一个新进程,以及终止当前进程,都是通过应用程序调用系统调用来实现的;
  • 有助于编写应用:操作系统为应用程序提供了强大的 ECF 机制,用来创建新进程、等待进程终止、通知其它进程系统中的一场时间,以及检测和响应这些时间。
  • 有助于理解并发:ECF 是计算机系统中实现并发的基本机制。在运行中的并发的例子有:中断应用程序执行的异常处理程序,在时间上重叠执行的进程和线程,以及中断应用程序执行的信号处理程序。
  • 有助于理解软件异常如何工作:像 try、catch、throw 等异常机制,软件异常允许程序进行非本地跳转(即违反通常的调用/返回栈规则的跳转)来响应错误情况。非本地跳转是一种应用层 ECF,在 C 中是通过 setjmp 和 longjmp 函数提供的。

8.1 异常

异常是异常控制流的一种形式,它一部分由硬件实现,一部分由操作系统实现。

异常(exception)就是控制流中的突变,用来响应处理状态中的某些变化。

在任何情况下,当处理器检测到有时间发生时,它就会通过一个张叫做异常表(exception table)的跳转表,进行一个间接过程调用(异常),到一个专门设计用来处理这类事件的操作系统子程序(异常处理程序(exception handler))。异常处理完毕后,根据事件的类型,会发生一下 3 种情况之一:

  1. 处理程序将控制返回给正常流的当前指令Icur,即当事件发生时正在执行的指令;
  2. 处理程序将控制返回给正常流的下一条指令Inext,即如果没发生异常将会执行的下一条指令;
  3. 处理程序终止被中断的程序

8.1.1 异常处理

系统为可能发生的每中类型异常都分配了一个唯一的非负整数的异常好(exception number)。其中一部分有处理器的设计者分配,其它则有操作系统内核(操作系统常驻内存的部分)的设计者分配

CPU异常:

  • 被零除
  • 缺页
  • 内存访问违例
  • 断点
  • 算数运算溢出

系统异常:

  • 系统调用
  • 外部 I/O 设备的信号

在系统启动时,操作系统会分配和初始化一张成为异常表(exception table)的跳转表,表目 k (exception number)包含异常 k 的处理程序的地址。

异常表的起始地址放在一个叫做异常表基址计算器(exception table base register)的特殊 CPU 寄存器中

异常与过程调用不同的地方:

  • 过程调用,在跳转处理程序之前,处理器将返回地址压入栈中。而异常处理是根据异常的类型,返回cur或者next指令
  • 处理器会将一些额外的处理器状态压入栈中,因为在返回正常流时需要用到。
  • 如果控制从用户程序转移到内核,所有这些项目都被压到内核栈中,而不是用户栈。
  • 异常处理程序运行在内核模式下,这意味着他们对多有的系统资源都有完全的访问权限。

异常处理程序处理完异常事件之后,它通过执行一条特殊的“从中断返回”指令,可选地返回到被中断的程序,该指令将适当的状态弹回到处理器的控制和数据寄存器中,如果异常中断的是一个用户程序,就将状态恢复为用户模式,然后在将控制返回给被中断的程序。

8.1.2 异常的类别

异常分为四类:

类别 原因 同步/异步 返回行为 中断(interrupt) 来自 I/O 设备的信号 异步 总是返回到下一条指令 陷阱(trap) 有意的异常 同步 总是返回到下一条指令 故障(fault) 潜在可恢复的错误 同步 可能返回到当前指令 终止(abort) 不可恢复的错误 同步 不会返回

中断

当网络适配器、磁盘控制器、或定时器芯片,通过向处理器芯片上的一个引脚发信号,并将异常号放到系统总线上,来触发中断,该异常号标识了引起中断的设备。

当指令完成执行后,处理器注意到中断引脚的电压变高了,就从系统总线读取异常号,然后调用适当的中断处理程序。处理程序返回时,它就讲控制返回给下一条指令。

相当于暂停,所以返回时从下一条指令开始,而故障则相当于错误,所以返回时从当前指令开始,以重复该过程

陷阱和系统调用

陷阱是有意的异常,是执行一条指令的结果。其最重要的用途是在用户程序和内核之间提供一个像过程一样的借口,即系统调用。

用户程序经常需要向内核请求服务,诸如:读取文件(read)、创建新进程(fork)、加载一个新程序(execve),或者终止当前进程(exit)。处理器为了这些对内核的受控访问提供了一条特殊的“syscall n” 指令,用户程序执行该指令时就会导致一个到异常处理程序的陷阱,这个处理程序解析参数,并调用适当的内核程序。

普通函数运行在用户态,用户态限制了函数可以执行的指令类型,只能访问与调用函数相同的栈;系统调用运行在内核态,内核态允许系统调用执行一些特权指令,以及访问内核栈。

故障

故障是有错误情况引起的,如果故障处理程序能够修正该错误,那么会返回当前指令,再次执行。否则,处理程序返回到内核中的 abort 例程,终止引起故障的应用程序。

终止

终止是由不可恢复的致命错误造成的。终止处理程序不会将控制返回给应用。而是直接返回给内核中的 abort 例程,今儿终止应用程序。(终止与故障修改失败的处理方式相同)

8.1.3 Linux/x86-64系统中的异常

共有256中不同的异常类型:

  • 0~31号异常由Intel脚骨师定义
  • 32~255号异常由操作系统定义的中断和陷阱。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK