CSAPP第八章:知识点总结
- 异常表中存储的是异常处理函数指针,系统启动的时候会在内存中分配和初始化这个表,表的起始地址存储在CPU的异常表基寄存器中
- 异常处理程序在内核态中运行,执行完后根据情况返回到异常发生的指令或者异常发生的下一条指令,或者直接退出。因此,异常处理程序根据情况push进对应的返回地址(并且还要push额外的处理器寄存器状态),push的stack是kernel stack
- 异常进一步分为三类:
1. Interrupt:一般是IO设备向处理器发送信号表示IO已经结束,返回到下一条指令
2. Trap:执行系统调用时需要先陷入内核态,然后陷入处理函数编码系统调用函数和传入的参数,并调用内核系统例程,结束后返回到下一条指令
3. Fault:有可能被修复的错误,比如说内存页缺失,如果Fault处理函数修复成功,则返回到Falut指令处,否则在内核中返回到执行到Aborts的例程,终止程序执行
4. Aborts:不可被修复的错误,一般是硬件错误,Aborts处理函数直接终止程序执行 - Linux中常用系统调用:read(), write(),open(),close(),stat(),mmap(),brk(),dup2(),pause(),……,不过一般这些系统调用都会被在标准库中封装成更一般的方法供开发者使用
- x86-64的Linux中对于系统调用的处理方法是:系统调用序列号存储在%rax寄存器中,函数参数依次存放在%rdi,%rsi,%rdx,%r10等寄存器中,执行系统调用时,先将这些寄存器装好,然后执行
syscall
指令,执行完内核程序后,返回值存放在%rax寄存器中。系统级函数如果出现错误,返回值一般为-1,errno作为全局变量会保存这个错误类型 - 进程的私有地址空间:操作系统会给每个进程分配一个私有的地址空间,这段地址空间不能由其它进程访问,进程地址空间由内核的虚拟内存和进程的虚拟内存组成
- 处理器会提供一个寄存器mode bit来标记当前进程是内核态还是用户态,当该位被置为1,进程在内核态执行,处于内核态的进程能够执行指令集中的所有指令,访问系统中所有内存;处于用户态的进程不允许执行特权指令,也不运行访问内核的地址空间
- 进程的上下文切换需要保存的信息有:通用寄存器值,浮点寄存器值,程序计数器值,用户栈,状态寄存器,内核栈,页表,进程控制表,文件表
fork()
创建的子进程除了PID和父进程不一致外,其余都一致,但是他们的地址空间是区别开的,指令执行序列也是随机的 ,getpid(), getppid()
分别获得进程号和父进程号- 进程处于terminated状态时不会释放资源,直到被父进程回收。子进程会向父进程发送exit status,然后释放资源。处于terminated状态但没有被回收的进程叫僵尸进程
- PID为1的进程叫做init进程,会回收那些父进程已经结束但是没有被回收的子进程、
waitpid()等待并回收子进程
- Shell是一个和用户进行交互的程序,它对于用户的命令处理大致可分为一下几步:
* 等待用户在stdin中输入信息,将输入信息(执行程序,参数列表)保存到字符串集合cmdline中,调用eval(char *cmdline)解析字符串
* eval函数中,首先调用builtin_command检查第一个输入字符串(命令)是否是内置命令,如果是则立即执行并返回1,不是则创建子进程,并将要求执行的程序在子进程中载入并执行;父进程根据输入命令中是否含有&决定是在后台执行还是前台执行,后台执行则shell不会等待函数执行而是直接返回