15

我对 linux 调度程序和其他一些类似的内核系统调用有一个一般性的问题。

linux调度程序是否被认为是一个“进程”,并且每次调用调度程序都需要一个上下文切换,就像它只是另一个进程一样?

假设我们有一个时钟滴答中断当前正在运行的用户模式进程,我们现在必须调用调度程序。对调度程序本身的调用是否会引发上下文切换?调度程序是否有自己的一组寄存器和 U 区域以及在每次调用时必须恢复的诸如此类的东西?

并且上述问题适用于许多其他系统调用。内核进程在上下文切换方面是否像常规进程一样,唯一的区别是它们拥有更多的权限和对 cpu 的访问权限?

我问这个是因为上下文切换开销很昂贵。调用调度程序本身会引发上下文切换以恢复调度程序状态,然后调度程序调用另一个进程来运行并再次调用另一个上下文切换,这听起来很奇怪。

4

3 回答 3

5

这是一个非常好的问题,除了硬件知道操作系统和任务调度程序的概念之外,答案将是“是”。

在硬件中,您会发现仅限于“主管”模式的寄存器。无需过多介绍内部 CPU 架构,这里有一份用于“用户模式”和“管理员模式”的基本程序执行寄存器的副本,后者只能由操作系统本身访问(通过内核设置的控制寄存器,它表示内核或用户模式应用程序当前是否正在运行)。

因此,您所说的“上下文切换”是交换/重置用户模式寄存器(指令寄存器,堆栈指针寄存器等)等的过程,但系统寄存器不需要换出,因为它们已存储除了用户。

例如,x86 中的用户模式堆栈是 USP - A7,而主管模式堆栈是 SSP - A7。因此内核本身(包含任务调度程序)将使用监督模式堆栈和其他监督模式寄存器来运行自己,在运行时将监督模式标志设置为 1,然后在用户模式硬件上执行上下文切换以在两者之间进行交换应用程序并将主管模式标志设置为 0。

但是在操作系统和任务调度的想法之前,如果你想做一个多任务系统,那么你必须使用你在问题中概述的基本概念:使用硬件中断每 x 个周期调用一次任务调度程序,然后将应用程序换成任务计划程序,然后换入新应用程序。但在大多数情况下,定时器中断将是您实际的任务调度程序本身,并且会对其进行大量优化,使其不再是上下文切换,而更像是一个简单的中断处理程序例程。

于 2012-05-31T18:47:33.313 回答
1

实际上,您可以schedule()kernel/sched.c. 它写得非常好,应该回答你的大部分问题。

但底线是 Linux 调度程序是通过调用调用的schedule(),它使用调用者的上下文来完成这项工作。因此没有专门的“调度程序”进程。这实际上会使事情变得更加困难——如果调度器是一个进程,它也必须自己调度!

schedule()被显式调用时,它只是将调用者线程 A 的上下文与选定的可运行线程 B 之一切换,例如它将返回到 B(通过恢复寄存器值和堆栈指针,返回地址schedule()将成为 B的返回地址)代替)。

于 2012-06-01T05:38:04.540 回答
1

下面是对调度程序调用期间发生的事情的简单描述的尝试:

  1. 当前具有上下文的程序正在处理器上运行。寄存器、程序计数器、标志、栈基等都适用于这个程序;除了操作系统原生的“保留寄存器”或类似情况之外,程序对调度程序一无所知。
  2. 调度程序功能的定时中断被触发。此时唯一发生的事情(在 vanilla 架构案例中)是程序计数器立即跳转到 BIOS 中断中列出的任何 PC 地址。这开始执行调度程序的“调度”子程序;其他所有内容都保持不变,因此调度程序会看到先前执行的程序的寄存器、堆栈等。
  3. 调度程序(与所有程序一样)具有一组对当前寄存器集进行操作的指令。这些指令的编写方式使得它们知道先前执行的应用程序已将其所有状态抛在脑后。调度程序中的前几条指令会将此状态存储在内存中的某个位置。
  4. 调度程序确定下一个程序应该有 cpu,获取它之前存储的所有状态并用它填充寄存器。
  5. 调度程序跳转到任务中列出的适当的 PC 计数器,该任务现在已在 cpu 上建立了完整的上下文。

概括地(过度)简化;调度程序不需要寄存器,它所做的只是将当前 cpu 状态写入预定的内存位置,从预定的内存位置加载另一个进程的 cpu 状态,然后跳转到该进程停止的地方。

于 2013-07-27T19:33:56.897 回答