进程调度2「Core」
Linux内核是一个支持多任务「multitasking」的操作系统,可以同时执行多个任务,但是CPU在某个时刻只能运行一个任务,因此为了使Linux内核真的看起来像多个任务在同时运行,调度器将连续不断地替换当前正在运行的任务,这个替换的过程被称为任务切换「task switch」或者调度「scheduling」。
内核通过处理定时器「timer」中断能够周期循环地检查当前进程的need_resched标志是否设置以及时间片「time slice」是否用尽,若当前进程设置了need_resched标志或者用完了时间片,那么将发生任务切换,这个过程就是利用定时器「timer」中断处理函数实现的周期调度「periodic scheduling 」。除此之外,内核还有很多其他代码会随时检查当前进程的need_resched标志是否设置,若need_resched标志被设置了,则将进行任务切换,这个过程属于非周期调度。在内核中这两种调度能够保证调度器尽可能经常地进行任务切换,以致于所有现存的进程能够尽可能公平地被执行。与周期调度不同,内核常见的非周期调度大致可分两种:被动式非周期调度和主动式非周期调度,比如如下所述的两个场景:
- 进程相关事件发生时会调用设置need_resched标志的函数,比如一个进程的状态发生了变化(进程唤醒事件出现、进程优先级改变)或者当前进程主动让出「yield」CPU执行时间,这只是触发了调度请求「scheduling request」,而真正的任务切换却发生于调用schedule()的函数,或检测need_resched标志是否设置的函数。
- 与前者不同的是有些代码(sleep、blocking API、lock API)会使当前进程进入睡眠状而不能继续执行,则会直接显式调用核心调度函数__schedule()进行任务切换。
下面给出了触发任务切换的调度点「scheduling point」,它们将检查need_resched标志是否被设置,如果设置的话,则会调用核心调度函数进行任务切换。
- 在中断处理完成后
- 在系统调用处理完成后
- 在使能内核抢占后
总之,本文主要分析使用timer中断实现的周期调度、非周期调度涉及的调度请求「scheduling request」以及任务切换。
- Target Platform: Rock960c
- **ARCH:**arm64
- **Linux Kernel:**linux-4.19.27
基于timer interrupt的周期调度
scheduler_tick()
非周期调度
调度的检查场合
任务唤醒
其他场景
调度器也会周期检查如下的情况是否需要进行调度。
- 任务显示地让出「yield」CPU执行时间
- 高优先级的任务插入运行队列
- 任务的优先级改变
- 任务的调度类改变
- 新创建的任务首次被执行
调度点「scheduling point」
arm64: factor work_pending state machine to C
arm64: convert raw syscall invocation to C
arm64: convert syscall trace logic to C
arm64: convert native/compat syscall entry to C