进程睡眠

本文主要总结引起进程睡眠的相关知识。

进程睡眠简介

进程睡眠的含义为:当前进程停止运行,系统将进行任务调度使另外一个任务运行。当唤醒睡眠的条件出现时,该进程将被唤醒,等待任务调度时恢复执行。
睡眠函数的核心在于触发任务调度,即调用schedule()函数,使系统当前运行的进程发生切换。

引起睡眠的操作

引起睡眠的操作

哪些流程禁止调用睡眠函数

上下文是什么

上下文是从英文context翻译过来,指的是一种环境。相对于进程而言,就是进程执行时的环境;具体来说就是各个变量和数据,包括所有的寄存器变量、进程打开的文件、内存信息等。
那为什么会有上下文呢?在介绍这个话题前,我们先了解一下下面几个知识。

内核空间和用户空间

我们知道现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟内存空间)为4G(2的32次方)。操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证用户进程不能直接操作内核,保证内核的安全,操作系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。针对Linux操作系统而言,将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为内核空间,而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为用户空间。每个进程可以通过系统调用进入内核,因此,Linux内核由系统内的所有进程共享。于是,从具体进程的角度来看,每个进程可以拥有4G字节的虚拟空间。空间分配如下图所示:

Linux内核分配图

有了用户空间和内核空间,整个Linux内部结构可以分为三个部分,从最底层到最上层依次是:硬件—>内核空间—>用户空间。如下图所示:

Linux内部结构图

特权级

Intel X86架构的CPU一共有0~3四个特权级,0级最高,3级最低,ARM架构也有不同的特权级,硬件上在执行每条指令时都会对指令所具有的特权级做相应的检查。硬件已经提供了一套特权级使用的相关机制,软件自然要好好利用,这属于操作系统要做的事情,对于UNIX/LINUX来说,只使用了0级特权级别和3级特权级别,即最高最低特权级。也就是说在UNIX/LINUX系统中,一条工作在0级特权级的指令具有了CPU能提供的最高权力,而一条工作在3级特权的指令具有CPU提供的最低或者说最基本权力。
以上是从CPU执行指令角度理解特权,其实虚拟地址到物理地址映射有mmu硬件实现,即分页机制是硬件对分页的支持,进程中有页表数据结构指向用户空间和内核空间,使用户态和内核态访问内存空间不同。

Linux特权级
现在我们从特权级的调度来理解用户态和内核态就比较好理解了,当程序运行在3级特权级上时,就可以称之为运行在用户态,因为这是最低特权级,是普通的用户进程运行的特权级,大部分用户直接面对的程序都是运行在内核态;反之,当程序运行在0级特权级上时,就可以称之为运行在内核态。
虽然用户态下和内核态下工作的程序有很多差别,但最重要的差别就在于特权级的不同,即权力的不同。运行在用户态的程序不能访问操作系统内核数据结构和程序。当我们在系统中执行一个程序时,大部分时间是运行在用户态下的。在其需要操作系统帮助完成某些它没有权力和能力完成的工作时就会切换到内核态。
Linux进程的4GB地址空间,3G-4G部分大家是共享的,是内核态的地址空间,这里存放着整个内核的代码和所有的内核模块,以及内核所维护的数据。用户运行一个程序,该程序所创建的进程开始是运行在用户态的,如果要执行文件操作,网络数据发送等操作,必须通过write,send等系统调用,这些系统调用会调用内核中的代码来完成操作,这时,必须切换到Ring0,然后进入3GB-4GB中的内核地址空间去执行这些代码来完成操作,完成后,切换回Ring3,回到用户态。这样,用户态的程序就不能随意操作内核地址空间,具有一定的安全保护作用。

为什么会有上下文

系统的两种不同运行状态,才有了上下文的概念。CPU对上下文环境进一步细分,因此有:
以下三种状态:

内核态,运行于进程上下文,内核代表进程运行于内核空间。
内核态,运行于中断上下文,内核代表硬件运行于内核空间。
用户态,运行于用户空间。

用户空间的应用程序,如果想请求系统服务,比如操作某个物理设备,映射设备的地址到用户空间,必须通过系统调用来实现。(系统调用是操作系统提供给用户空间的接口函数)。通过系统调用,用户空间的应用程序就会进入内核空间,由内核代表该进程运行于内核空间,这就涉及到上下文的切换,用户空间和内核空间具有不同的地址映射,通用或专用的寄存器组,而用户空间的进程要传递很多变量、参数给内核,内核也要保存用户进程的一些寄存器、变量等,以便系统调用结束后回到用户空间继续执行。交互如下图所示:

用户态和内核态交互

进程上下文

所谓的进程上下文,就是一个进程在执行的时候,CPU的所有寄存器中的值、进程的状态以及堆栈上的内容,当内核需要切换到另一个进程时,它需要保存当前进程的所有状态,即保存当前进程的进程上下文,以便再次执行该进程时,能够恢复切换时的状态,继续执行。

一个进程的上下文可以分为三个部分:用户上下文、寄存器上下文以及系统级上下文:

用户级上下文:正文、数据、用户堆栈以及共享存储区;
寄存器上下文:通用寄存器、程序寄存器(IP)、处理器状态寄存器(EFLAGS)、栈指针(ESP);
系统级上下文:进程控制块task_struct、内存管理信息(mm_struct、vm_area_struct、pgd、pte)、内核栈。

当发生进程调度时,进行进程切换就是上下文切换(context switch)。
操作系统必须对上面提到的全部信息进行切换,新调度的进程才能运行。而系统调用运行的是模式切换(mode switch)。模式切换与进程切换比较起来,容易很多,而且节省时间,因为模式切换最主要的任务只是切换进程寄存器上下文的切换。
在进程上下文中,可以用current宏关联当前进程,也可以睡眠,也可以调用调度程序。

中断上下文

硬件通过触发信号,向CPU发送中断信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理。所以,“中断上下文”就可以理解为硬件传递过来的这些参数和内核需要保存的一些环境,主要是被中断的进程的环境。
内核进入中断上下文是因为中断信号而导致的中断处理或软中断。而中断信号的发生是随机的,中断处理程序及软中断并不能事先预测发生中断时当前运行的是哪个进程,所以在中断上下文中引用current是可以的,但没有意义。
在中断上下文,通常都会始终占用CPU(当然中断可以嵌套,但我们一般不这样做),不可以被打断。不可以睡眠或者释放CPU。

为什么中断上下文不能调用可以睡眠的函数呢?

中断的处理流程:

1.进入中断处理程序
2.保存关键上下文
3.开中断(sti指令)
4.进入中断处理程序的handler
5.关中断(cli指令)
6.写EOI寄存器(表示中断处理完成)
7.开中断

硬中断

对应于上图中的1、2、3步骤,在这几个步骤中,所有中断是被屏蔽的,如果在这个时候睡眠了,操作系统不会收到任何中断(包括时钟中断),系统就基本处于瘫痪状态(例如调度器依赖的时钟节拍没有等等……)

软中断

对应上图的4(当然,准确的说应该是4步骤的后面一点)。这个时候不能睡眠的关键是因为上下文。
操作系统以进程调度为单位,进程运行在进程的上下文中,以进程描述符作为管理的数据结构task_struct。进程可以睡眠的原因是操作系统可以切换不同进程的上下文,进行调度操作,这些操作都以进程描述符为支持。
中断运行在中断上下文,没有一个所谓的中断描述符来描述它,它不是操作系统调度的单位。一旦在中断上下文中睡眠, 首先无法切换上下文(因为没有中断描述符,当前上下文的状态得不到保存),其次,没有人来唤醒它,因为它不是操作系统的调度单位。此外,中断的发生是非常非常频繁的,在一个中断睡眠期间,其它中断发生并睡眠了,那很容易就造成中断栈溢出导致系统崩溃。
如果上述条件满足了(也就是有中断描述符,并成为调度器的调度单位,栈也不溢出了,理论上是可以做到中断睡眠的),中断是可以睡眠的,但会引起很多问题:
例如,你在时钟中断睡眠了,那操作系统的时钟就乱了,调度器也就失去了依据;
例如,你在一个IPI(处理器间中断)中,其他CPU都在死循环等你答复,你却睡眠了,那其他处理器也不工作了;
例如,你在一个DMA中断中睡眠了,上面的进程还在同步的等待I/O的完成,性能就大大降低了……还可以举出很多例子。
所以,中断是一种紧急事务,需要操作系统立即处理,不是不能做到睡眠,是它没有理由睡眠。
不过,在Linux调度器的具体实现的时候,检测到了在中断上下文中调度schedule函数也并没有强制Linux进入panic,可能是linux开发者认为一个好的内核调度器无论如何也尽自己最大的努力让系统运行下去吧。但是,在厂商自己提供的内核中,往往修改调度器行为,在中断上下文中检测到调度就直接panic了,对于内核开发者而言,这样更好,可以尽早的发现问题。

-------------本文结束感谢您的阅读-------------

本文标题:进程睡眠

文章作者:

发布时间:2025年02月20日 - 02:02

最后更新:2019年12月16日 - 01:12

原始链接:http://wangzaifa.com/2025/02/20/%E8%BF%9B%E7%A8%8B%E7%9D%A1%E7%9C%A0/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

坚持原创技术分享,您的支持将鼓励我继续创作!
0%