淘宝客有必须做网站吗,天晴创艺网站建设百度小程序,香河家具城网站建设目标,新手初做网站目录 信号的处理时机
引入
思考 -- 什么时候才能算合适的时候呢?
用户态转为内核态
引入
内核地址空间
引入
思考 -- 进程为什么能切换成内核态呢?
虚拟地址空间
注意点
原理 (总结一下)
为什么如何进入内核态
引入
介绍
底层原理(int 80)
cpu的寄存器
用…目录 信号的处理时机
引入
思考 -- 什么时候才能算合适的时候呢?
用户态转为内核态
引入
内核地址空间
引入
思考 -- 进程为什么能切换成内核态呢?
虚拟地址空间
注意点
原理 (总结一下)
为什么如何进入内核态
引入
介绍
底层原理(int 80)
cpu的寄存器
用户级
内核级
如何知道进入了内核态
硬件上
软件上
用户态和内核态的来回切换
为什么
如何切换
信号的处理流程
介绍
详细图解
描述
默认操作
忽略操作
自定义操作
抽象图解
交叉点处
方向
横线 信号的处理时机 引入 之前我们说过,信号被os发送到进程,实际上是修改了pending信号集然后进程会在合适的时候处理那究竟什么时候才能算合适的时候呢? 思考 -- 什么时候才能算合适的时候呢? 处理信号必然不是我们做的,而是os,因为信号是内核数据那么处理信号时,就得处于内核的范畴,不然怎么访问os的数据也就是处于内核态那么肯定也会存在用户态,和内核态对应,也就存在内核态和用户态的切换那么内核态就拥有三种阶段 -- 刚进入内核态,在内核态执行任务时,准备转为用户态时 那么是哪个阶段开始处理信号的呢? 一般是在执行完任务后,内核态准备转为用户态时,会进行信号的处理(因为任务肯定第一位嘛,信号的处理又不急于这一时) 用户态转为内核态 引入 虽然我们是这样说的 -- 由内核态转为用户态时,就会处理信号但是这个操作我们看不到,怎么知道到底有没有转换呢?说到底,究竟是怎么转换的呢?未免有点太抽象了 内核地址空间 引入 其实并不抽象,所有看起来复杂的行为都是将[底层一些简单的操作]封装而成的比如,可以首先来思考这个问题 -- 进程为什么能切换成内核态呢? 思考 -- 进程为什么能切换成内核态呢? 内核态,也就是可以使用os内部的数据/接口 那为什么一个进程,它可以有这样的行为呢? 肯定是它此时的权限修改成了os的权限 如何使用os内部的数据/接口呢? 要使用这些,必然是和使用普通数据/接口一样,要访问实际的内存的毕竟他们本质没有区别,只是权限不一样而访问内存必须通过虚拟地址空间页表MMU实现我们无法直接操作物理内存!!既然可以访问内核数据,那内核肯定也有自己的进程空间页表 那到底有没有呢? 有的! 虚拟地址空间 之前学习的地址空间中本身就有1G的空间,是存放内核空间的: 也就是说,我们切换为内核态,依赖的是 -- 进程地址空间有内核空间 注意点 既然有内核空间,自然也有内核级的页表用来映射 但是要注意!!! 每个进程的用户空间,对应的是独立的内存块 难道每个进程拥有的内核空间,它对应的内存也是独立的吗? 不会的!内核资源是所有进程共用的,不会让每个进程去瓜分一部分[进程的独立性]要求用户空间对应的内存都是独立的,但每个进程可以使用相同的os资源所以,内核级的页表只需要一份(因为对应的物理内存是同一块),它可以被所有进程看到所以,无论进程如何切换,我们看到的都是同一份os资源 原理 (总结一下) 进程可以切换为内核态的原因就在于,每个进程中都有内核地址空间只要切换访问位置和访问权限,自然可以通过内核地址空间访问内核数据噜 为什么如何进入内核态 引入 知道了进程是可以切换的 那么究竟为什么要切换成内核态,底层又是如何切换的呢? 介绍 当我们需要访问内核数据时,就需要进入内核态 我们大多都是通过系统调用接口,来使用内核数据的所以,调用系统调用,自动就可以进入内核态(因为之前在使用的时候,并没有什么特殊行为) 并且,我们不用把系统调用想的那么神秘,他也只是一个函数而已(只不过非常接近底层)系统调用和使用库函数本质上没有区别,都是在进程自己的地址空间内进行跳转的 底层原理(int 80) 在每个系统调用函数开始前,都需要先切换成内核态它通过int(interrupt 的缩写) 80 这个汇编指令,来切换成内核态而汇编的底层是通过cpu的寄存器实现的 cpu的寄存器
实际上存在两套寄存器,用户级的和内核级的 用户级 实际上,我们将[平时写的简单代码]转换为汇编指令,里面用到的eax等等,就是用户级的寄存器 内核级 存放与权限/控制相关数据的寄存器,我们看不见 内核级寄存器里面有一个CR3它用来表示当前cpu的访问权限 -- 内核/用户所以实际上int 80汇编指令,就是通过修改CR3寄存器的数据,来进入内核态 如何知道进入了内核态 硬件上 通过CR3寄存器的数据得知的(寄存器是硬件的一部分) 软件上 其实我们已经在上面介绍了,只要检测执行的位置是否指向内核空间即可指向内核空间,就说明此时正在执行系统级别的代码,此时也就处于内核态 用户态和内核态的来回切换 为什么 总不能从用户态切到内核态后,我们就不切回来了吧 我们肯定还有很多没有执行的用户级代码呢 如何切换 其实原理我们已经都介绍过了只要我们可以拿到进程执行相关的数据,我们也就可以按照上面的原理 -- 跳转地址空间,修改寄存器数据,来切换状态(当然这里只是一个大概,实际上非常复杂的)刚好cpu的寄存器里面,就存放着很多进程执行相关的数据结构的指针(也就是进程的上下文) 信号的处理流程
知道了原理后,我们就可以明白,os究竟是如何处理信号的
介绍 详细图解 描述 首先我们要先陷入内核态(可能是系统调用,也可能是异常/中断导致的)然后在内核态下,os完成一系列的任务在即将返回用户态,继续向下执行代码前,我们正好处于内核态下,有能力,可以顺手处理收到的信号所以,os开始处理信号! os先去检查信号在内核中的两种信号集 -- pending,block如果该信号被阻塞,os可以直接返回到用户态但如果满足条件,我们拿到对应信号的处理函数后这里就要分情况讨论了: 默认操作 如果需要终止进程,os可以直接进行终止进程的调度如果该进程中有需要刷新数据/dump到外设,os在内核态下可以直接操作,操作完再退出进程如果该进程不退出,也是一样的:eg:有个信号用来暂停进程,也可以在内核态下直接实现,直接修改进程状态,然后调度下一个进程 忽略操作 如果是忽略,os只需要将pending信号集由1改为0,即可返回到用户态,执行下面的代码噜 自定义操作 如果是自定义的操作,就有点麻烦了因为默认和忽略都可以在内核态下直接完成,因为os的权限是最大的,什么资源都可以拿到但是在执行自定义函数时,需要转换到用户态才行 为什么要转换到用户态呢?内核态下不能执行吗? 内核态当然可以执行进程的代码,它可以拿到所有的资源但是,万一该函数中有违规操作(用户态下不可以执行的操作)却没有被内核态下的进程识别到,就可能会导致不好的后果为了避免这些情况,普通代码还是让用户态进程执行的好 在用户态下执行完成后,也就该返回内核态了 不仅是因为,处理完信号后,需要修改pending位图也在于,进程需要返回到陷入内核态的执行位置,然后继续向下执行而这些操作都需要访问os资源 抽象图解 将信号处理过程 -- 从信号需要从用户态陷入到内核态 - 处理完信号,返回原先的执行位置 抽象出来,得到该图: 交叉点处 就是os开始处理信号的时候 方向 图中的箭头,就是os执行流的变化方向 横线 如果用一条横线贯穿该图,那么横线上方就是用户态,下方就是内核态(可以看到信号处理的时候是在内核态中)横线与图的四个交点就可以代表,进程的状态变化次数而交点所在的方向,就代表了状态的切换方向