异常控制流·八

来源:互联网 发布:mac系统xampp使用教程 编辑:程序博客网 时间:2024/06/05 21:49
第8章 异常控制流
关键词:异常控制,异常处理,上下文切换,进程控制,并发进程

8.1异常

1 定义
异常是一种形式的异常控制流,它一部分是由硬件实现的,一部分是由操作系统实现的。它们有一部分是由硬件实现的,所以具体细节将随系统的不同而有所不同。然而,对于每个系统而言,基本的思想都是相同的。
异常就是控制流中的突变,用来响应处理器状态中得3 某些变化。
异常控制流(exceptional of flow,ECF)
在任何情况中,当处理器检测到有事件发生时,处理器正在执行某个当前指令Icuur。在处理器中,状态被编码为不同的位和信号。状态变化被称为事件(event),时间可能和当前指令的执行直接相关。比如,发生虚拟存储器缺页、算术溢出或者一条指令试图除以0。另一方面,事件可能和当前指令没有关系。比如一个系统定时器产生信号或者一个I/O请求完成。
2 异常处理
在任何情况下,当处理器检测到有事件发生时,它就会通过一张叫做异常表(exception table)的跳转表,进行一个间接过程调用(异常),到一个专门设计用来处理这类事件的操作系统子程序——异常处理程序(exception handler)。当异常处理程序完成后,根据引起异常的事件的类型,会发生以下三种情况的一种:
(1)处理程序将控制返回给当前指令Iccur(当事件发生时正在执行的指令)
(2)处理程序将控制返回给Inext(如果没有发生异常将会执行下一条指令)
(3)处理程序终止被中断的程序
3 异常好与异常处理
系统中可能的每种类型的异常都分配了一个唯一的非负整数的异常好(exception number)。这些号码中的某一些是由处理器的设计者分配的,其它号码由操作系统内核(操作系统场驻存储器的部分)的设计者分配的。
异常号是到异常表中的索引,异常表的起始地址放在一个叫做异常表基址寄存器(exception table base register)的特殊CPU寄存器里。
异常类似于过程调用,但是有一些重要的不同之处:
(1)过程调用时,在跳转到处理程序之前,处理器将返回地址压到栈中。
(2)处理器也罢一些额外的处理器状态压到栈里,在处理器程序返回时,重新开始被中断的程序会需要这些状态。
(3)如果控制从一个用户转移到内核,所有这些项目(item)都被压到内核栈中,而不是压到用户栈中。

(4)异常处理程序运行在内核模式下,这意味着他们对所有的系统资源都有完全的访问权限。

4 异常的类别
表1 异常属性总结

类别

原因

异步/同步

返回行为

中断

来自I/O设备的信号

异步

总是返回到下一条指令

陷阱

有意的异常

同步

总是返回到下一条指令

故障

潜在可恢复的异常

同步

可能返回到下一条指令

终止

不可恢复的错误

同步

不会返回

8.2 进程

1 进程的基本概念
进程的经典定义就是一个执行中程序的实例。系统中的每个程序都是运行在某个进程的上下文中的。上下文是由程序正确运行所需的状态组成的。这个状态包括存放在存储器中的程序的代码和数据、它的栈、它的通用目的寄存器的内容、它的程序计数器、环境变量以及打开文件描述符的集合。
每次用户通过向shell输入一个可执行目标文件的名字,运行一个程序时,shell会创建一个新的进程,然后在这个新进程的上下文中运行这个可执行目标文件。应用程序还能够创建进程,且在这个新进程的上下文中运行它们自己的代码或其它应用程序。
进程提供给应用程序的关键抽象:
一个独立的逻辑控制流,它提供一个假象,使我们矩的我们的程序独占地使用处理器。
一个私有的地址空间,它提供一个假象,使我们觉得我们的程序独占地使用存储器系统。
2 逻辑控制流
任何逻辑流在时间上和另外的逻辑流重叠的进程被成为并发进程(concurrent process),而这两个进程就被称为并发运行。
进程和其它金恒轮换运行的概念被称为多任务(multitasking)。一个进程执行它的控制流的一部分的每一段时间叫做时间片(time slice)。因此,多任务也叫做时间分片(time slicing)。
3 上下文切换
操作系统内核利用一种成为上下文切换的较高级形式的异常控制流来实现多任务。
内核为每个进程维持一个上下文。上下文就是内核重新启动一个被抢占进程所需的状态。它由一些对象的值组成,这些对象包括通用目的寄存器、浮点寄存器、程序计数器、用户栈、状态寄存器、内核栈和各种内核数据结构。
在进程执行的某些时刻,内核可以决定抢占当前进程,并重新开始一个先前被抢占的进程。这种决定叫做调度(scheduling),是由内核中成为调度器(scheduler)的代码处理的。当内核选择一个新的进程时运行时,我们就说内核调度了这个进程。在内核调度了一个新的进程运行之后,它就抢占当前进程,并使用一种称为上下文切换的机制来将控制转移到新的进程,上下文切换可以:(1)保存当前进程的上下文;(2)回复某个先前被抢占进程所保存的上下文;(3)将控制传递给某个新恢复的进程。

8.3 进程控制

Unix系统:
获取进程ID:getid和getpid
创建和终止进程
回收子进程
让进程休眠
加载并运行程序
利用fork和execve运行程序

8.4 信号

1 发送信号和接收信号
发送信号:内核通过更新母的进程上下文中的某个状态,发送(递送)一个信号给目的进程。发送信号可以有如下两种原因:(1)内核检测到一个系统事件,比如除零错误或者子进程终止。(2)一个进程调用了kill函数,显式地要求内核发送一个信号给目的进程。一个进程可以发信号给他自己。
接收信号:当目的进程被内核强迫以某种方式对信号的发送作出反应时,目的进程就接收了信号。进程可以忽略这个信号,终止,或者通过执行一个称为信号处理程序(signal handler)的用户层函数捕获这个信号。
一个只发出而没有被接受的信号叫做待处理信号(pending signal)。在任何时刻,一种类型至多只会有一个待处理信号。一个进程可以有选择性地阻塞接收某种信号。
一个待处理的信号最多只能被接收一次。
当一个程序要捕捉多个信号时会出现以下的问题:(1)待处理信号被阻塞;(2)待处理信号不会排队等待;(3)系统调用可以被中断。

8.5 操作进程的工具

Unix系统提供了大量的监控和操作进程的有用工具:
strace:打印一个程序和它的紫禁城调用的每个系统调用的轨迹。
ps:列出系统中当前的进程(包括僵死进程)
top:打印出关于当前进程资源使用的信息
kill:发送一个信号给进程
/proc(Linux和Solaris):一个虚拟文件系统,以ASCII文本格式输出大量内核数据结构的内容,用户程序可以读取这些内容。

8.6 小结

异常控制发生在计算机系统的各个层次。在硬件层,异常是由处理器中的事件触发的控制流中的突变。控制流传递给一个软件处理程序,该处理程序进行一些处理,然后返回给被中断的控制流。
有四种不同类型的异常:中断、故障、终止、陷阱。当一个外部的I/O设备,例如定时器新片或者一个磁盘控制器,设置了处理器芯片上的中断管脚时,(对于任意指令)中断层会异步地发生。控制返回到中断指令的下一条指令。执行一条指令可能导致故障和终止的发生。故障处理程序会重新开始故障指令,而终止处理程序从不将控制返回给中断的流。最后,陷阱就像是用来实现系统调用的函数调用,系统调用提供给应用到操作系统代码的受控入口点。
在操作系统层,内核提供关于一个进程的基础性概念。一个进程提供给应用两个重要的抽象:(1)逻辑控制流,它提供给每个程序一个假象,好像它是在独占地使用处理器;(2)私有地址空间,提供给每个程序一个假象,好像它是独占地使用主存。
在操作系统和应用之间的接口处,应用可以创建子进程,等待他们的紫禁城暂停或者终止,运行新的程序,并捕捉来自其它进程的信号。信号的语义是微妙的,并且随系统不同而不同。然而,在与POSIX兼容的系统上还存在着一些机制,允许程序清楚地指定期望的信号处理语义。
最后在应用层,C程序可以使用非本地跳转来规避正常的调用/返回栈规则,并且直接从一个函数转移到另一个函数。
参考文献
布赖恩特, O'Hallaron D, et al. 深入理解计算机系统[M]. 中国电力出版社, 2004.
Bryant R, David Richard O H, David Richard O H. Computer systems: a programmer's perspective[M]. Upper Saddle River: Prentice Hall, 2003.