异常

异常的发生和捕捉,是在硬件层面完成的。但是异常的处理,是由软件来完成的
异常处理
异常表
IO发出的信号异常代码,是由操作系统来分配的,像加法移除的异常代码,由CPU触发
根据异常代码在异常表里找到相应的处理代码

异常处理似乎很像一个函数调用,但异常处理需要:
- 把 CPU 内当前运行程序用到的所有寄存器,都放到栈里面
- 像陷阱涉及用户态内核态的异常处理的栈要压到内核里
- 像故障这样的异常,在异常处理程序执行完成之后。从栈里返回出来,继续执行的不是顺序的下一条指令,而是故障发生的当前指令
异常的类别
| 类别 | 原因 | 异步/同步 | 返回行为 | 
|---|---|---|---|
| 中断 | 来自I/O设备的信号 | 异步 | 总是返回到下一条指令 | 
| 陷阱 | 有意的异常 | 同步 | 总是返回到下一条指令 | 
| 故障 | 潜在可恢复的错误 | 同步 | 可能返回到当前指令 | 
| 终止 | 不可恢复的错误 | 同步 | 不会返回 | 



Linux/X86-64系统中的异常
- 除法错误
- 一般保护故障
- 缺页
- 机器检查
Linux 中的系统调用
进程
一个执行中程序的实例
逻辑控制流
逻辑控制流。进程为每个程序提供了一种假象,好像程序在独占地使用处理器
并发流
一个逻辑流的执行在时间上与另一个流重叠
私有地址空间
进程为每个程序提供一个假象,好像它独占使用了系统的全部内存
用户模式与内核模式
寄存器中的一个模式位,设置该模式位可以用来切换用户模式或是内核模式
上下文切换
内核使用上下文切换来实现多任务
系统调用错误处理
包装系统调用进行错误处理
进程控制
- 获取进程ID  
- 创建和终止进程 - void exit(int status); // 终止 pid_t fork(void); // 创建新子进程
- 回收子进程 - pid_t waitpid(pid_t pid,int *statusp,int options);
- 让进程休眠 - unsigned int sleep(unsigned int secs); int pause(void);
- 加载并运行程序 - execve(cont char *filename,const char *argv[],const char *envp[]); // 使用当前的进程运行新的程序
信号术语
- 发送信号 - 进程组 - pid_t getpgrp(void);
- 用kill发送信号 - /bin/kill -9 1235
- 用kill函数发送信号 - int kill(pid_t pid,int sig);
- 用alarm函数 - unigned int alarm(unsigned int secs);
 
- 接收信号 - sighandler_t signal(int signum,sighandler_t handler);
- 阻塞信号和解除阻塞信号 - 隐式阻塞
- 显式阻塞
 
- 编写信号处理程序 - 安全
- 正确
- 可移植
 
- 同步流 
- 显式等待信号 
非本地跳转
用户级异常控制流形式
// 保存当前调用环境,供后面的longjmp调用
int setjmp(jmp_buf env);
int sigsetjmp(sigjmp_buf env,int savesigs);
void longjmp(jmp_buf env,int retval);
void siglongjmp(sigjmp_buf env,int retval);