目录
信号的递达流程:
信号在什么时候递达?
用户态和内核态:
内核态、用户态在页表的映射关系:
操作系统如何得知当前执行状态是用户态还是内核态?
操作系统如何处理被捕捉的信号?
信号的递达流程:
-
信号被生成后加入未决信号集,等待处理。
-
如果信号被阻塞,则暂时不能递达;如果没有被阻塞,则可以递达并处理。
-
如果信号未被阻塞,先从未决信号集中移除信号,再依据可处理信号集的设定执行默认操作或调用自定义处理函数。
-
如果信号被阻塞,解除阻塞后,该信号需要被“立即”递达。
信号在什么时候递达?
-
进程在内核态返回到用户态时,进行信号的检测和处理。
用户态和内核态:
-
用户态是一种受控的状态,所能够访问的资源有限。
-
内核态是操作系统的工作状态,能够访问大部分的系统资源。
内核态、用户态在页表的映射关系:
-
系统调用是在进程的地址空间内发起的,但用户态的进程只能访问用户态的虚拟地址空间(通常是0到3GB)。当通过系统调用从用户态切换到内核态时,进程会进入操作系统内核的上下文,从而可以访问更高的地址空间(通常是3GB到4GB的内核空间)。这个切换是通过硬件机制完成的,例如使用中断或陷入指令。
-
在x86架构下,每个进程都有自己独立的页表,用户态代码只能访问页表的用户空间部分。当进程切换到内核态时,此时可以访问页表的内核空间的地址范围。每个进程的页表包含用户态和内核态的映射。
-
代码的执行确实都发生在进程的地址空间内,但在用户态执行的是用户代码,系统调用切换到内核态时,执行的则是内核代码。虽然它们共享同一个进程地址空间,但所执行的代码属于不同的权限级别。
操作系统如何得知当前执行状态是用户态还是内核态?
-
在x86架构中,cs寄存器包含当前执行代码所在段的权限级别,而这个权限级别可以用来区分用户态和内核态。在Linux系统中,Ring 0(00)是内核态,Ring 3(11)是用户态。
-
用户进程不能直接修改
cs
寄存器。操作系统通过中断、陷入(trap)、或系统调用等机制从用户态切换到内核态。CPU会自动修改cs
寄存器,从Ring 3切换到Ring 0。这种切换是硬件级别的。 -
操作系统通过读取cs寄存器来得知当前执行代码时的状态。
操作系统如何处理被捕捉的信号?
-
当进程捕捉到某个信号并定义了自定义的信号处理函数时,操作系统如果要递达这个信号。操作系统会切换到用户态来执行这个自定义的信号处理函数。执行完成后通过sigreturn返回到内核态,再由内核态返回到之前的执行点。
-
这么做的原因是:信号处理函数是用户代码,为了防止用户有越权行为,操作系统不会直接在内核态处理用户的自定义函数。