异常控制流概念:

通常情况下控制流是平滑的(即每条相邻指令的内存地址也是相邻的),但是也有突变的情况。而这种有突变的控制流就是异常控制流Exceptional Control Flow,ECF(如程序中的跳转,调用和返回;硬件产生的中断等)。

ECF的好处:

8.1 异常

那到底异常的类型与这3种情况是怎么对应的?(8.1.2有描述)

8.1.1 异常处理

异常表:

8.1.2 异常的类型

中断:中断的异常处理一般称为中断处理程序。收到中断时,会先把当前指令完成后,再将控制流突变到中断处理程序。

2.陷阱

陷阱是有意执行一条命令的异常,最重要的用途是给用户程序提供系统调用(如syscall,read,write,execve,exit等)。

系统调用与普通的函数调用的区别:

普通的函数调用运行在用户模式下,限制了函数可以执行的指令的类型,且只能访问与调用函数相同的栈;而系统调用在内核模式中,允许系统调用执行特殊指令,并访问定义在内核的栈。

执行内核代码(内核也是程序),访问内核空间,称为内核模式(Kernel Mode)。

当执行应用程序自己的代码时,称为用户模式(User Mode)。程序很多情况下,都需要使用系统调用进入内核模式来完成特定的功能(需要输入输出、申请内存等比较底层的操作时)。

系统调用:

C语言可以使用syscall函数调用任何的系统调用,但标准C库提供了一组方便的包装函数(下表),系统调用如果发生错误会返回-4095到-1之间的错误码,且系统调用返回的任何错误代码存储在errno,可以通过strerror(errno)获取错误码对应的错误信息(字符串英文信息)。

#include <sys/syscall.h>                 /* For SYS_xxx definitions */

int syscall(int number, ...);

如:     tid = syscall(SYS_gettid);

C语言中常见的两个执行shell命令的函数:

int system(const char * string)

FILE *popen(const char * command, const char* type)

为何要有用户模式和内核模式?

一个计算机系统,会有大量的程序同时运行,而内核空间存放的是操作系统内核代码和数据,是被所有程序共享的,直接在程序中修改内核空间中的数据不仅会影响操作系统本身的稳定性,还会影响其他程序,这是非常危险的行为,所以操作系统禁止用户程序直接访问内核空间。因此用户程序想要获得系统资源,就必须通过系统调用,来进入到内核模式,统一由内核来进行管理,保证内核空间的数据不会被随意修改,才能保证操作系统本身和其他程序的稳定性。

3.故障

故障是由错误情况引起的,当故障发生时,处理器把控制权交给故障处理程序,如果能被修正,则控制返回给引起故障的指令,从而重新执行它,否则返回到内核的abort例程,终止程序。

比如读取数据时的缺页异常为最常见的故障;程序中的段错误。

4.终止

终止一般是由硬件错误所引起的,不可恢复的致命错误造成的结果。

比如DRAM或者SRAM位被损坏时发生的奇偶错误。

8.1.3 linux/X86-64系统中的异常

0-31的异常号,是由Intel架构师定义的异常,32-255对应的是操作系统定义的中断和陷阱。

8.2 进程

context通俗的理解就是运行的环境。

进程提供给程序的关键抽象:

 8.2.1 逻辑控制流

用调试器单步执行程序时,我们会看到一系列的程序计数器PC的值,这些PC值唯一地对应于包含在程序的可执行目标文件的指令,或是包含在运行时动态链接到程序的共享对象中的指令。这个PC值得序列就叫做逻辑控制流,或简称逻辑流。

下图为三个进程对应的三个逻辑流执行的情况。

8.2.2 并发流

8.2.3 私有地址空间

进程为每个程序提供它自己的私有地址空间,该空间是不被其他进程读写的。每个这样的空间都有相同的通用结构。

一个可执行文件本质上都是由代码段、数据区和未初始化数据区三部分组成的

.bss段(未初始化数据区):通常用来存放程序中未初始化的全局变量和静态变量的一块内存区域。.bss段属于静态分配,程序结束后静态变量资源由系统自动释放。

.data段:存放程序中已初始化的全局变量的一块内存区域。数据段也属于静态内存分配。

代码段:存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域属于只读。在代码段中,也有可能包含一些只读的常数变量(指.rodata)。

栈区:由编译器自动释放,存放函数的参数值、局部变量等。每当一个函数被调用时,该函数的返回类型和一些调用的信息就会被压栈,然后这个被调用的函数再为他的自动变量和临时变量在栈上分配空间。栈区是从高地址位向低地址位增长的,是一块连续的内存区域,最大容量是由系统预先定义好的(Linux下通过ulimit -s命令可以查询,一般是4M或者8M),申请的栈空间超过这个界限时会提示溢出。

堆区:用于动态分配内存,由程序员申请分配和释放。堆是从低地址位向高地址位增长,采用链式存储结构。频繁的malloc/free会造成内存空间的不连续,产生外部碎片。当申请堆空间时库函数是按照一定的算法搜索可用的足够大的空间。因此堆的效率比栈要低的多。

共享库的内存映射区域:是运行程序时,需要加载的动态共享库的内存映射区域。关于是如何映射的,此处不讨论。

8.2.4 用户模式与内核模式

8.2.5 上下文切换

下图为上下文切换的例子:

 8.3 系统调用错误处理

当系统级函数遇到错误时,通常会返回-1,并设置全局整数变量errno来表示出了什么错。

错误处理包装函数:

对需要被调用的函数,定义一个具有相同参数的函数,但函数名的第一个字母为大写,并检查错误。

8.4 进程控制

获取进程ID:

创建与终止进程:

C语言中能让进程停止的函数:

int pause(void);

unsigned int sleep(unsigned int seconds);

创建子进程

终止进程

 回收子进程:

waitpid函数等待子进程结束:

pid为所需等待的子进程PID号

options为修改该函数默认行为的参数

statusp是指向已回收子进程的退出状态值

进程休眠:

加载并运行程序:

fork和execve结合运行程序:

8.5 信号

更高层的软件形式的异常,称为linux信号,它允许进程和内核中断其他进程。

信号提供了一种机制,把低层的异常通知到用户进程。

下图为linux支持的30中信号类型:(常见的SIGINT(Ctrl+C)和SIGKILL(kill -9命令))

发送信号与接收信号:

 进程组:每个进程都只属于一个进程组。

获取当前进程所在的进程组ID

改变指定进程的进程组ID

linux中使用ps命令查看进程

UID 进程用户ID
PID 进程ID 
PPID 父进程ID
PGID 进程组ID
TTY 进程所属的控制台
STIME 进程启动时间

不同系统的PS命令的信息可能不一样,还有top 命令也是用来看进程的信息的。

前台和后台进程:

发送信号:

使用bin/kill 发送信号:kill -9 pid

使用键盘发送信号:Ctrl + C,Ctrl + Z

使用C语言中kill函数给指定进程发送信号:kill(pid,SIGKILL)

使用C语言alarm函数给自己发送信号:alarm(1),一秒后给自己发送一个SIGALRM信号

接收信号:

信号处理的默认行为有以下几种:

通过signal函数可以改变信号的处理方式

下图为信号处理程序的信号处理流程:

阻塞和解除阻塞信号:

8.6 非本地跳转

sig开头的函数是在信号处理函数中使用的。goto语句跳转到当前函数的一个标志。而jmp是可以直接跳转到其他函数。

setjmp函数会把当前调用的环境保存在env缓冲区中,若是直接调用setjmp返回值为0,若是通过longjmp跳转的,会返回longjmp中的retval值。

例1 setjmp和longjmp:输出结果为“Detected an error2 condition in foo”

例2 sigsetjmp和siglongjmp 输出结果为

 8.7 操作进程的工具

习题:

答案:AB:否,AC:是,AD:是,BC:是,BD:是,CD:是。

答案:5次。

深入理解计算机系统--第八章异常控制流相关推荐

  1. CSAPP:第八章 异常控制流1

    CSAPP:第八章 异常控制流1 关键点:异常 8.1 异常8.2 进程   现代系统通过使控制流发生突变来对这些情况做出反应,一般而言,我们把这些突变称为异常控制流(Exceptional Cont ...

  2. 第八章 异常控制流 笔记

    异常控制流存在于操作系统的方方面面,最底层的机制称为异常(Exception),由硬件和操作系统共同实现.另外还有: 进程切换(Process Context Switch): 硬件计时器和操作系统实 ...

  3. 《深入理解计算机系统》第八章——异常控制流知识点总结

    课本习题: 8.11 #include <unistd.h> #include <stdio.h>int main(){int i;for(i=0;i<2;i++) fo ...

  4. 理解计算机系统第八章(家庭作业)

    不说明的话则默认为进程执行图下面是父进程上面是子进程 8.11 #include "csapp.h" int main(){int i;for(i = 0;i< 2; i++ ...

  5. 深入理解计算机系统简述

    第一章 计算机系统漫游 由GCC编译的C程序"Hello, World" ,通过研究程序的生命周期,介绍计算机系统的主要概念和主题. 第二章 信息的表示和处理 讲述了计算机的算术运 ...

  6. 深入理解计算机系统(CSAPP)含lab详解 完结

    文章目录 深入理解计算机操作系统-第一章 1.1 信息就是位 + 上下文 1.2 程序被其他程序翻译成不同的格式 1.3 了解编译系统如何工作是大有益处的 1.4 处理器读并解释储存在内存中的指令 1 ...

  7. 《深入理解计算机系统》----总结

    第一章     计算机系统漫游 主要内容:主要是全面精炼的概括了本书的内容,也就是"计算机系统概述",包括: a)      解释计算机系统中"信息"的概念:就 ...

  8. 计算机系统性错误,《深入理解计算机系统-异常》

    现代操作系统通过使控制流发生突变来对某些意外情况(磁盘读写数据准备就绪.硬件定时器产生信号等)做出反应.一般而言,我们把这些突变命名为异常控制流(Exceptional Contral Flow EC ...

  9. 计算机系统:异常控制流

    从给处理器加电开始,直到你断电为止,程序计数器假设一个值的序列 其中,每个是某个相应的指令的地址.每次从到的过渡称为控制转移(control transfer).这样的控制转移序列叫做处理器的控制流( ...

最新文章

  1. python记录当前系统时间 生成照片直接命名
  2. matlab 基础知识查漏
  3. SolrJ查询Solr数据
  4. .如何在Linux上安装Postman应用程序?
  5. 手机 滑动_真的滑动屏,华为手机柔性屏新的专利布局
  6. Oracle buffer状态深入剖析
  7. postgresql集群方案hot standby初级测试(二) ——处理数据能力
  8. autocad自动图框_AutoCAD中的小技巧,你用过几个?
  9. Faster R-CNN原理
  10. oracle安装选取字符集,oracle10g字符集问题及设置PL/SQL、sqlplus字符集
  11. 拓端tecdat|R语言预测期货波动率的实现:ARCH与HAR-RV与GARCH,ARFIMA模型比较
  12. 计算机dll修复工具,百度dll修复工具(百度电脑专家)
  13. 身份证文字信息及人脸图片采集
  14. 云部署中的 公有云 私有云 混合云 社区云 基本概念快速掌握
  15. 快速高效入门3D建模学习教程,让你最快从小白到建模大师!
  16. 计算机图形学学习笔记(5.1)几何造型与样条
  17. matlab均值方差模型,matlab预测ARMA-GARCH 条件均值和方差模型
  18. 黑龙江移动新魔百盒M411A_2+8_S905L3A_线刷固件包
  19. 如何在路由器上做端口映射
  20. 勇斗勒索软件的英雄疑因旧罪被捕;华为、腾讯为用户数据起冲突

热门文章

  1. 第一篇博客:那些年磕过的题之Fence Painting
  2. 互联网起源之构建在电磁波之上
  3. C语言的HelloWorld
  4. 计算机科学与技术专业修读指南,计算机类专业培养方案修读指南.pdf
  5. phpwind论坛发帖脚本(loadrunner)
  6. 假如我写2007年高考作文题
  7. 还记得儿时的梦想吗?
  8. 基于python的有道词典接口爬取
  9. 修改代码的艺术(奋斗的小鸟)_PDF 电子书
  10. Python运用openpyxl计算excel表格中的欧氏距离