【深入理解计算机系统】第八章 异常控制流

程序计数器的一个值序列:,其中是某个相应指令的地址,其中,到的过度为控制转移,这样的控制转移序列叫处理器的控制流。当和不相邻时(发生了突变),则发生了跳转、调用、返回这样的程序指令,这些突变称之为异常控制流(ECF)。异常控制流可以发生在:硬件层,硬件检测到的事件会触发控制突然转移到异常处理程序;操作系统层,内核通过上下文切换将控制从一个进程转移到另一个进程;应用层,一个进程发送信号到另一个进程。

1、异常

异常就是控制流的突变,用来响应处理器状态中的某些变化。
【深入理解计算机系统】第八章 异常控制流_第1张图片

I c u r r I_{curr} Icurr 触发了某些事件,这些事件包括:内存缺页、算数溢出、除0、系统信号、I/O请求等。当处理器检测到事件,则通过异常表(异常表中的非负整数代表了每种类型的异常,异常表的起始地址存放在异常表基址寄存器)跳转到异常处理程序。之后处理程序的行为有:

  • 返回控制至 I c u r r I_{curr} Icurr
  • 返回控制至 I n e x t I_{next} Inext
  • 终止应用程序

【深入理解计算机系统】第八章 异常控制流_第2张图片
【深入理解计算机系统】第八章 异常控制流_第3张图片
异常相较于过程调用的区别:

  • 过程调用跳转前会将处理器返回地址压入栈中;异常根据类型,返回当前指令或者下一条指令
  • 处理器会把一些额外的状态压入栈中,用于重新执行用户程序时,恢复环境
  • 控制从用户转移到内核,所有的项目将压入内核栈,而不是用户栈
  • 异常在内核模式下执行,它对系统资源都有完全的访问权限

1.1、异常的类别

异常分为:中断、陷阱、故障、终止。
【深入理解计算机系统】第八章 异常控制流_第4张图片

陷阱一般由系统调用引起,故障的典型示例就是缺页异常(可修复的错误),终止一般是硬件错误。注意除0异常是故障,因为该异常会返回一个信号,默认是终止成程序,如果愿意捕获该信号并处理,程序就能正常运行。x86-64系统定义了256中异常,0-31由Intel架构师定义,32-255是操作系统定义的中断和陷阱。
【深入理解计算机系统】第八章 异常控制流_第5张图片
【深入理解计算机系统】第八章 异常控制流_第6张图片

2、进程

进程是一个运行的程序,进程的状态是一个集合包括:代码、数据、栈、通用目的寄存器的内容、程序计数器、环境变量及文件描述符。
【深入理解计算机系统】第八章 异常控制流_第7张图片
为了使用户态的进程访问内核数据结构,Linux提供了/proc的文件系统,例如CPU类型为/proc/cpuinfo,或者进程使用的内存段/proc//maps,/sys则输出关于系统总线和设备的额外底层信息。

2.1、上下文切换

多任务基于上下文切换实现,上下文就是内核重新启动一个被抢占的进程所需的状态,状态包括:通用目的寄存器、浮点寄存器、程序计数器、用户栈、状态寄存器、内核栈、内核数据结构(页表、进程表、文件描述符等)。系统调用和中断都有可能触发上下文切换。
【深入理解计算机系统】第八章 异常控制流_第8张图片

2.2、通过execve加载运行程序

通过execve加载filename后,主函数变为:

int main(int argc, char **argv, char **envp);

【深入理解计算机系统】第八章 异常控制流_第9张图片
linux提供了getenv、setenv、unsetenv函数用于操作环境变量字符串

3、信号

【深入理解计算机系统】第八章 异常控制流_第10张图片

一个发出而没有被接收的信号叫待处理信号,任何时刻,一种类型的至多只有一个待处理信号,如果一个进程有一个k类型信号,那么任何接下来发送到该进程的 k 类型信号都会被丢弃。一种信号被阻塞时,它仍可以被发送,但是待处理信号不会被接收,直到进程取消对这种信号的阻塞。

一个待处理信号只会被接收一次。内核为每个进程在pending位向量中维护着待处理信号的集合,而在blocked位向量中维护着被阻塞的信号集合,只要传送了一个k类型的信号,内核设置pending中的k位,接收了k类型的信号,内核就清楚pending位。

当内核把进程p切换到用户态时,会检查信号集合(pending & ~blocked),执行信号处理函数,其中SIGSTOP和SIGKILL不可以被修改,信号处理函数可以通过singal修改。
【深入理解计算机系统】第八章 异常控制流_第11张图片

阻塞和解除阻塞信号

linux可以显示和隐式阻塞信号:

隐式阻塞:内核默认阻塞任何当前处理程序正在处理的信号类型的待处理信号,

显示阻塞:使用sigprocmask和它的辅助函数明确阻塞和解除阻塞信号
【深入理解计算机系统】第八章 异常控制流_第12张图片

编写信号处理函数要:

  • 尽可能的简单,

  • 使用异步信号安全的函数,原因:1.可重入(可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误,只访问局部变量;不可重入的代码使用了一些系统资源,比如全局变量区,中断向量表等)2.信号处理程序不能中断。(printf、sprintf、malloc、exit都在此列)
    【深入理解计算机系统】第八章 异常控制流_第13张图片

  • 保存和恢复当前的errno

  • 阻塞所有的信号,保护对共享全局数据结构的访问

  • 用volatile声明全局变量

  • 用sig_atomic_t声明标志,处理程序写全局标志记录收到的信号,主程序周期性读并响应信号,再清除该标志。
    【深入理解计算机系统】第八章 异常控制流_第14张图片

该函数可以另主线程显示等待一段时间

4、非本地跳转

一种用户级的异常控制流形式,称为非本地跳转,它将控制直接从一个函数转移到另一个正在执行的函数,而不需要经过正常的调用-返回序列。
【深入理解计算机系统】第八章 异常控制流_第15张图片
setjmp 函数再 env 缓冲区保存当前调用的环境,以供 longjmp 使用,并返回 0。setjmp 返回的值不能被赋值给变量,不过可以再switch或条件语句中测试。
【深入理解计算机系统】第八章 异常控制流_第16张图片
longjmp从 env 缓冲区恢复调用环境,然后触发一个从最近一次初始化 env 的 setjmp 调用的返回,然后 setjmp 返回,并带有非零的反掌 retval。

非本地跳转的重要应用就是让一个深层嵌套的函数调用立即返回,例如检测到错误。我们可以把try catch 看作 setjmp函数,把 throw 看成 longjmp 函数。

5、操作进程的工具

STRACE:不用再说了

ps:显示进程

top:打印关于进程资源使用信息

pmap:显示进程的内存映射

你可能感兴趣的:(书籍阅读,系统架构)