个人主页:Lei宝啊
愿所有美好如期而遇
前言:
Linux信号(产生)-CSDN博客
Linux信号(保存)-CSDN博客
前面我们解释了信号的产生和保存,接下来我们就要解释信号的处理,关于操作系统在合适的时候对信号进行处理,合适的时候是什么时候?怎么处理?
我们先把这张图贴出来,后面我们会结合这张图进行讲解。
信号在什么时候被处理呢?是进程从内核态切换到用户态的过程中,信号会被检测并处理,我们给出一张图来解释:
我们将上面的图截出一部分来:内核空间部分的执行就是内核态,用户空间部分的执行就是用户态,当执行OS系统部分的代码时,就处于内核态,执行结束将要返回用户代码,也就是用户态时,操作系统会检查进程信号,并对信号做出处理,信号如果是默认动作或者忽略,那么在内核中执行默认系统调用后进行返回,如果是自定义动作,那么会从内核态切换到用户态去执行用户代码,这里为什么要切换呢?内核态也就是OS,权限应该很高,按照道理来讲,是可以执行用户代码的,但是,用户的代码如果可以被OS信任,那么系统调用还用来做什么?正是因为这点,如果用户代码有越权非法操作,内核去以他的权限去执行,那么会产生未定义结果,所以这是不被允许的。切换到用户态后,执行完用户代码后,然后返回内核态,再由内核态的系统调用返回用户态上一次执行代码的位置,然后接着向下执行。
那么这里有一个问题:既然我们有系统调用,可以直接kill进程,为什么还要向进程发送信号,通知进程我要kill掉你?这是因为,如果进程在执行临界区代码,如果我们直接kill进程,会有未定义结果产生,所以需要给进程发送信号,在进程执行完临界区代码,从内核态返回用户态时,再去处理信号,再去调用系统调用kill进程。
上图,我们还有一个问题:用户空间和内核空间的代码在进程地址空间中可以通过页表的映射在物理内存中找到,那么,是不是说,用户甚至可以访问到内核空间的OS代码?为了防止这样的事情发生,所以有权限去约束,简单点来说,就是CPU中有一个CS寄存器,低位的两个比特位存储0和3,表示内核态和用户态,在执行内核态代码时,会先查看是否处在内核态,否则不可以执行。
那么现在,在进程地址空间中,我们可以找到OS和用户的代码,在执行时,统一在地址空间内进行跳转。同时,要提到的是,内核级页表,所有进程都是同一张,OS在进程地址空间中的空间布局都是相同的,所以任意一个进程都可以进行系统调用,只需要找到他的函数指针数组,知道他的系统调用号,就可以执行,实际上是这样的:
在处在内核态时,找到read的系统调用号,并产生内部中断,reo寄存器中存放0x80中断号,根据这个中断号去OS的中断向量表中索引方法, 找到系统调用表,根据系统调用号索引找到系统调用执行。
我们最终可以得出一个结论:进程无论怎样切换,总能找到操作系统,我们访问操作系统的本质就是通过我们进程的地址空间中的内核空间。
那么我们再提出几个问题:OS是进程吗?OS有PCB表吗?OS会自己管理自己吗?操作系统也需要CPU执行,那么OS和其他进程是同时执行吗?
首先,OS不是进程,只有在OS启动完成后,才有了进程的管理这种说法,但是OS有自己的PCB表,以及OS会自己管理自己。OS实际上是一个死循环,我们可以在他的源码中看到这样的代码:for(;;) pause(); 也就是说,他是死循环暂停的,但是,由于CPU中存在时钟,会不断地以高频率向CPU发送中断,于是OS就会识别这些中断,并根据中断号进行一系列进程调度,以及内存管理等等,在中断到来时,不管进程执行到什么代码,哪怕是临界区代码,都会暂停,转而去执行操作系统的处理中断的代码,操作系统如果收到调度进程的中断号,就会去查看当前进程的时间片是否耗尽,如果没耗尽,则继续执行,否则,将他的数据保存在PCB当中,从CPU上剥离下来,转而去执行其他进程。所以,OS和进程并不是同时执行的。
而信号就是模拟硬件中断而产生的,进程处理信号,CPU处理硬件中断,进程处理信号根据三张位图共同决定信号递达,再索引处理方法,硬件中断根据中断号索引中断向量表,找到处理方法。