30

我试图了解 linux 内核中的调度过程实际上是如何工作的。我的问题与调度算法无关。它是关于功能schedule()switch_to()工作方式的。

我会尽力解释。我看见了:

当进程用完时间片时,标志need_resched由 设置scheduler_tick()。内核检查标志,发现它已设置,并调用schedule()(与问题 1 相关)切换到新进程。这个标志是一个消息,应该尽快调用调度,因为另一个进程应该运行。在返回用户空间或从中断返回时,need_resched检查标志。如果设置了,内核会在继续之前调用调度程序。

查看内核源代码(linux-2.6.10 - 《Linux内核开发,第二版》一书所基于的版本),我还看到一些代码可以schedule()自愿调用该函数,赋予另一个进程运行的权利。我看到该函数switch_to()是实际执行上下文切换的函数。我查看了一些依赖于架构的代码,试图了解switch_to()实际在做什么。

这种行为引发了一些我无法找到答案的问题:

  1. 完成switch_to()后,当前正在运行的进程是什么?调用的过程schedule()?还是下一个流程,即被选中运行的流程?

  2. schedule()被中断调用时,要运行的选定进程在中断处理完成时开始运行(在某种 RTE 之后)?还是在那之前?

  3. 如果schedule()函数不能从中断中调用,标志何时need_resched设置?

  4. 当定时器中断处理程序工作时,正在使用什么堆栈?

不知道能不能说清楚。如果我不能,我希望我能在一些答案(或问题)之后做到这一点。我已经查看了几个试图理解该过程的来源。我有《Linux Kernel Development, sec ed》一书,我也在使用它。如果这有助于解释,我对 MIP 和 H8300 架构有所了解。

4

1 回答 1

37
  1. 调用后switch_to(),内核堆栈切换到 中命名的任务的堆栈next。更改地址空间等在 eg 中处理context_switch()
  2. schedule()不能在原子上下文中调用,包括从中断中调用(参见签入schedule_debug())。如果需要重新调度,则设置 TIF_NEED_RESCHED 任务标志,该标志在中断返回路径中进行检查。
  3. 见 2。
  4. 我相信,使用默认的 8K 堆栈,可以使用当前正在执行的任何内核堆栈来处理中断。如果使用 4K 堆栈,我相信会有一个单独的中断堆栈(由于一些 x86 魔法而自动加载),但我并不完全确定这一点。

为了更详细一点,这里有一个实际的例子:

  1. 发生中断。CPU 切换到一个中断蹦床例程,它将中断号压入堆栈,然后 jmps 到common_interrupt
  2. common_interrupt 调用do_IRQ,它禁用抢占然后处理 IRQ
  3. 在某个时候,会做出切换任务的决定。这可能来自定时器中断或唤醒呼叫。在任何一种情况下,都会调用set_task_need_resched,设置 TIF_NEED_RESCHED 任务标志。
  4. 最终,CPU 从原来的中断中的 do_IRQ 返回,并进入IRQ 退出路径。如果这个 IRQ 是从内核中调用的,它会检查 TIF_NEED_RESCHED 是否设置,如果是,则调用preempt_schedule_irq,它在执行schedule().
  5. 如果 IRQ 是从用户空间调用的,我们首先检查在返回之前是否需要做任何事情。如果是这样,我们转到retint_careful,它会检查挂起的重新调度(并schedule()在需要时直接调用)以及检查挂起的信号,然后返回另一轮retint_check直到没有设置更重要的标志。
  6. 最后,我们恢复 GS 并从中断处理程序返回

至于switch_to()switch_to()(在 x86-32 上)所做的是:

  1. 保存 EIP(指令指针)和 ESP(堆栈指针)的当前值,以供我们稍后返回此任务时使用。
  2. 切换 的值current_task。至此,current现在指向新的任务。
  3. 切换到新堆栈,然后将我们要切换到的任务保存的 EIP 推送到堆栈上。稍后会进行返回,使用这个EIP作为返回地址;这就是它跳回之前调用的旧代码的方式switch_to()
  4. 调用__switch_to()。此时,current指向新任务,我们在新任务的堆栈中,但其他各种 CPU 状态尚未更新。__switch_to()处理切换诸如 FPU、段描述符、调试寄存器等的状态。
  5. 从 中返回时__switch_to()switch_to()手动压入堆栈的返回地址被返回,将执行放回switch_to()新任务之前的位置。切换到的任务现在已完全恢复执行。

x86-64 非常相似,但由于 ABI 不同,必须做更多的状态保存/恢复。

于 2011-06-29T22:17:09.597 回答