LKD(Linux内核设计与实现) Chapter 4 Process Scheduling

当其他任务的优先级变得比当前优先级高的时候,抢占就有可能发生。当这种优先级发生变化时,need_resched标识会被设置,内核会在合适的时候抢占当前运行任务,换其他任务运行。

need_resched会在以下几种情况被设置:

  • 每次系统时钟到来时,调度器重新计算各任务的运行时间,那些运行时间不足的任务优先级将提高。如果当前任务不是最高优先级的任务,need_resched标识会被设置。对应的处理函数是schedule_tick()
  • 当一个更高优先级的任务从等待队列中被唤醒时,need_resched标识会被设置。对应的处理函数是try_to_wake_up()

need_resched被设置后,抢占并不会马上进行,因为内核要确保当前的状态是安全的。

基本上,一个任务会处于三种状态:

  • 在内核任务上下文情境下,任务为了等待资源而阻塞,这时本来就是要切换到其他任务,抢占没有任何问题。
  • 在内核任务上下文情境下,任务主动调用schedule()来调度其他任务运行。这是否安全,取决于写这行代码的人是否知道自己在做什么!
  • 当从内核情境(中断上下文和任务上下文)切换到用户空间时,内核即将进入不活动状态,这时候可以选择任何任务在用户空间运行,抢占是安全的。
  • 当从内核中断上下文回到内核任务上下文的时候,抢占有可能会发生。
  • 上面所有的抢占都是在特定情形下发生,是if能抢占then抢占的思路。从2.6开始,Linux开始支持全抢占逻辑,即if没有说不能抢占then就可以抢占。每个任务的thread_info里加了一个计数器preempt_count,如果当前任务没有说自己不能被抢占(即preempt_count为0),那么抢占随时会发生。

  • 文章中涉及的任何代码都参考Linux v4.4
  • switch_to()用来切换处理器状态(恢复和保存寄存器值)。
    • include/asm-generic/switch_to.h (通用定义)
    • arch/x86/include/asm/switch_to.h (X86体系结构下的定义)
  • switch_mm()用来切换页表状态。
    • include/asm-generic/mmu_context.h (通用定义)
    • arch/x86/include/asm/mmu_context.h (X86体系结构下的定义)
  • 感谢http://asciiflow.com/提供Ascii Diagram创作服务。
  • http://www.makelinux.net/books/lkd2/?u=ch10lev1sec8
  • daf94cf87写的内核抢占
  • http://kernelnewbies.org/FAQ/Preemption