第八章 异常控制流
异常的类别
- 中断(interrupt):来自I/O设备的信号,异步,总是返回下一条指令
- 陷阱(trap):有意的异常,同步,总是返回到下一条指令。如系统调用
- 故障(fault):潜在可以恢复的错误,同步,可能返回到当前指令。如缺页异常
- 终止(abort):不可恢复的错误,同步,不会返回
进程
- 并发流:concurrent flow
- 并行流:parallel flow
Linux进程地址空间
用户模式和内核模式
处理器通常用某个控制寄存器的一个模式位(mode bit)来提供用户模式和内核模式的切换。
进程控制
- 运行(running)
- 停止/挂起(suspended)
- 终止(abort)
Linux回收子进程
- 当一个进程终止时,保持在终止状态,由它的父进程回收(reaped)。终止未回收的进程称为僵尸进程(zombie)。
- 如果一个父进程终止,内核安排init进程成为孤儿进程的养父。Init进程系统启动时由内核创建,不会终止,是所有进程的祖先。
信号
信号(signal)通知进程系统中发生了某种类型的事件
- 发送信号:内核通过更新目的进程上下文中的某个状态,发送一个信号给目的进程
- 接收信号:目的进程被内核强迫以某种方式对信号的发送作出反应
- 待处理信号(pending signal):任何时候至多只会欧一个待处理信号,待处理信号的实现是用信号掩码(signam mask)实现的,每种类型的信号只占用一个比特位
安全/正确/可移植信号处理
- 处理函数尽可能简单
- 处理函数只调用异步信号安全函数,即能被信号处理函数安全调用:可重入或者能被中断。如printf/malloc/exit都不是安全的。
- 保存和恢复errno,如果处理函数再次调用系统调用,可能会修改errno,需要事先保存并在退出时恢复
- 阻塞所有信号,保护共享全局结构的访问
- volatile声明全局变量,信号处理函数更新全局变量,外部可能会继续使用缓存的全局变量。volatile期望每次使用全局变量都从内存中获取
sig_atomic_t声明标志位
进程只能接收一个pending的信号,后续再有相同信号,将会被丢弃,不能用信号来对发生的事件进行计数
- 正确处理竞争
- 非本地跳转,采用setjmp()/longjmp()方式进行跳转并快速恢复