1. 异常控制流
控制流:处理器从加电到断电,只是简单的读取和执行一个指令序列(每次执行一条指令),这个指令序列就是处理器的控制流。
改变控制流的两种机制:
- 跳转和分支(Jumps and branches)
- 调用和返回(Call and return)
能够对(由程序变量表示的)程序状态的变化做出反应。
不足之处:难以对系统状态的变化做出反应。(如磁盘或网络适配器的数据到达、除零错误、键盘输入、系统定时器超时等)
为了应对这些不足之处,现代计算机系统需要针对“控制流发生突变”的情况作出反应,称为“异常控制流”机制。
异常控制流的分类:按照各异常控制流机制发生的计算机系统层次进行分类:
底层机制(硬件层):
- 异常(Exceptions):硬件检测到的事件会触发控制转移到异常处理程序;由操作系统和硬件共同实现。
高层机制:
- 进程切换(Process context switch):通过操作系统和硬件定时器实现。
- 信号(Signals):操作系统实现。
- 非本地跳转(Nonlocal jumps):setjmp()和longjmp() ;利用C运行库实现。
2. 异常(Exceptions)
异常是指为响应某个事件将控制权转移到操作系统内核中的情况。(如被除零、算术运算溢出、缺页、IO请求完成、键盘输入等)
1. 异步异常–中断(Interrupts)
处理器外部I/O设备引起的异常。由处理器的中断引脚指示;中断处理程序返回到下一条指令处。
Examples:
- 时钟中断:定时器芯片每隔几毫秒触发一次中断;内核从用户程序取回控制权。
- 外部设备的I/O中断:键盘敲击Ctrl+C、网络数据包到达、磁盘数据到达。
2. 同步异常–陷阱(Traps)
- 有意的,执行指令的结果
- Example:系统调用(System call)(读写文件、打开关闭文件等),用户程序和内核之间的一个接口
- 陷阱处理程序将控制权返回到下一条指令。
3. 同步异常–故障(Faults)
- 不是有意的,但有可能被修复
- Example:缺页(可恢复)、保护故障(不可恢复)、浮点异常。
- 处理程序要么重新执行引起故障的指令(已修复),要么终止。
4. 同步异常-- 终止(Aborts)
- 非故意,不可恢复的致命错误导致的。
- Example:非法指令,奇偶校验错误、机器检查。(非法内存引用)
- 终止当前程序。
3. 进程(Processes)
定义:一个执行中程序的实例。(A process is an instance of a running program.)
进程提供给应用程序两个关键抽象:
- 逻辑控制流:每个程序似乎独占地使用CPU;通过OS内核的上下文切换机制提供。
- 私有地址空间:每个程序似乎独占地使用内存系统;由OS内核地虚拟内存机制提供。
单处理器在并发地执行多个进程:
- 进程交错执行
- 地址空间由虚拟内存系统管理
- 未执行进程地寄存器值保存在内存中
多核处理器:
- 单个芯片有多个CPU
- 共享主存,有的还共享cache
- 每个核可以执行独立的进程kernel负责处理器的内核调度
4. 进程控制(Processes Control)
1. 创建进程
父进程通过调用fork函数创建一个新的运行的子进程。
int fork(void)
- 子进程返回0,父进程返回子进程地PID
- 新创建的子进程几乎但不完全与父进程相同
(子进程得到与父进程虚拟地址空间相同但是独立的一份副本;子进程获得与父进程任何打开问及那描述符相同的副本;子进程有不同于父进程的PID)
fork函数:调用一次,返回两次
2. 回收子进程
- 父进程执行回收(using wait or wait pid)
- 父进程收到子进程的退出状态
- 内核删掉僵死子进程、从系统中删除掉它的所有痕迹
如果父进程不回收子进程:
- 如果父进程没有回收它的僵死子进程就终止了,内核安排init-养父进程去回收他们(init进程的PID为1,系统启动时创建,不会终止)
- 长时间运行的进程应当主动回收它们的僵死子进程
父进程回收子进程方式(通过wait/waitpid函数回收子进程):
int wait(int *child_status)
- 挂起当前进程的执行直到它的一个子进程终止/停止
- 返回已终止/停止子进程的pid
- 如child_status != NULL,则在该指针指向的整型量中写入关于终止原因和退出状态的信息
pid_t waitpid(pid_t pid, int &status, int options)
挂起当前进程直到指定进程终止才返回,有多种选项。
3. 加载并运行程序
int execve(char *filename, char *argv[], char *envp[])
在当前进程中载入并运行程序:loader加载器函数。
Loader删除子进程现有的虚拟内存段,创建一组新的段(栈与堆初始化为0),并将虚拟地址空间中的页映射到可执行文件的页大小的片chunk,新的代码与数据段被初始化为可执行文件的内容,然后跳到_start………… 除了一些头部信息实际没读文件,直到缺页中断;
并且覆盖当前进程的代码、数据、栈。
调用一次从不返回!!!
5. 小结
- 创建进程 fork:调用一次,返回两次
- 进程退出 exit:调用一次,从不返回
- 加载运行程序 execve:调用一次,从不返回
588

被折叠的 条评论
为什么被折叠?



