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