内核态和用户态
用户所处的状态就是用户态,内核所处的状态就是内核态。而用户态和内核态存在的意义就是限制不同程序的访问权限。例如,当执行用户自己的代码时,进程所处的状态就是用户态,而当用户的代码中包含系统调用时,可能需要调用内核的代码,而调用内核的代码需要内核级别的权限,此时进程就需要转换成内核态。
举一个形象的例子,一个用户去银行取钱,从哪个账户取,取多少都是由用户自己决定的,这个阶段就是执行用户自己的代码,处于用户态。但是当用户提出取钱的要求之后,需要银行的工作人员帮他取钱,这时,取钱需要工作人员的权限,用户的权限就不够了。所以用户提出取钱的要求就是在调用内核的代码,这时就需要内核级别的权限,进入内核态。总之,当用户的代码中有自己的代码,也有涉及内核的代码,那这些代码由谁负责,谁有权限,就由谁来执行。
总体来看,内核态执行的是操作系统的代码,权限较高,用户态执行的是普通用户的代码,权限较低。因此用户态无法访问内核态的代码。但是需要注意的是,进程处于内核态的时候,也不能访问用户态的代码。其原因是基于这样一点认识“操作系统默认所有用户都是恶意的”,如果处于内核态的进程执行了用户态的代码,那这些代码在内核中执行,就可能会对操作系统造成损害。
用户自己做自己的事情,就处于用户态,一旦涉及操作系统,那就处于内核态。
什么时候需要用户态和内核态之间的切换?
1,进程切换:当一个进程的时间片到了的时候,就需要将其切换下去,再把其它进程切换上来,再切换下去之前,需要保存进程当前的临时数据和上下文信息。具体过程如下:
(1)通过该即将被换下去的进程找到其虚拟地址空间,找到虚拟地址空间中的1G内核空间。通过内核空间所对应的内核页表的映射找到管理进程的操作系统代码。
(2)在当前进程的上下文空间中执行相应的代码,通过执行这些代码来保存进程的上下文信息和临时数据。
(3)换上另一个进程,这时需要加入当前进程的进程控制块,将进程的上下文信息和临时数据加载进来。在这之后进程就可以在用户态运行。
即当进程正常运行,行使功能的时候,都是处于用户态的,但当进程需要进行进程切换时上下文信息、临时数据的保存,恢复新切换上来的进程的上下文信息和临时变量时进程是处于内核态的。
2,进程对信号的处理:首先明确一点,进程在运行的时候,就是单纯的在运行,无法估计其它事务,只有当涉及时间片的切换或出现异常情况,进程暂时没有在运行的时候才能有机会对信号进行处理。进程处理信号的具体过程如下:
(1)由于时间片的切换或异常情况的出现,导致进程进入内核态,当进程在内核态处理完问题之后,需要对那些之前收到却被暂时挂起的信号进行处理。
(2)对于一个传递给进程的信号而言,分为三种情况:默认、忽略、按照自定义方式处理。如果是前两种,那就直接默认或忽略即可。如果是第三种,那所谓的自定义信号处理方式就需要到用户代码种寻找,这时处于内核态的进程就需要进入内核态,以便于寻找并执行用户自定义的信号处理方式。
(3)在对信号处理完毕之后,进程理应当是返回用户态正常执行任务的,虽然在处理自定义信号的时候,进程当前就处于用户态,但是这样的状态和默认状态下回到用户态的逻辑是不同的。因处理信号而回到用户态的进程并不在主控制流程中。所以该进程必须要再次进入内核,亦即回归主线,再通过内核返回用户态,到达刚刚进入内核态之前进程所运行到的下一行代码中,然后在用户态继续运行即可。