1.开场白
环境:
处理器架构:arm64
内核源码:linux-5.11
ubuntu版本:20.04.1
代码阅读工具:vim+ctags+cscope
我们或许经常听说过内核抢占,可是我们是否真正理解它呢?内核抢占和抢占式内核究竟有什么关系呢?抢占计数器究竟干什么用?… 本文我们就来好好讨论下,关于内核抢占的一些技术细节,力求让大家理解内核抢占。
注:本文主要关注CFS调度类。
2.内核抢占和抢占式内核
我们经常使用uname -a命令能看到“PREEMPT”的字样,没错,我们使用的是抢占式内核。
# uname -a
Linux (none) 5.11.0-g08a3831f3ae1 #1 SMP PREEMPT Fri Apr 30 17:41:53 CST 2021 aarch64 GNU/Linux
那什么是抢占式内核呢? 实际上,支持内核抢占的内核叫做抢占式内核,不支持内核抢占的内核叫做不可抢占式内核。那么问题又来了,什么是内核抢占呢?我们都知道,拿周期性的tick来说:对于用户任务,当每个时钟中断到来后都会检查它的实际运行时间是否超过理想运行时间,或者运行队列中有没有优先级更高的进程,一般如果满足其中一个条件就会设置重新调度标志,然后在中断返回用户态的前夕发生调度,这是所谓的用户任务抢占。但是如果处于一个内核态的任务正在运行,这个时候发生中断唤醒了一个高优先级的任务,那么这个被唤醒的任务能否被调度执行呢?这个时候就会分两种情况分析,如果是抢占式内核那么高优先级任务就有可能抢占当前任务而调度执行(之所有是有可能是因为两者虚拟运行时间差值要大于抢占粒度才允许抢占),如果是不可抢占式内核那么不允许抢占,除非当前进程执行完或者主动发生调度高优先级进程该有机会被调度。也就是说,支持内核抢占的内核不仅允许在用户态的任务可以被抢占,处在内核态的任务也允许被抢占(请注意这里说的是内核态,因为用户空间任务可以通过系统调用等进入内核态),这样对于交互性或者低延迟的应用场景很友好,如手持设备和桌面应用,响应会很快。而对于服务器来说,它就对吞吐量要求较高,希望获得更多的cpu时间,而交互性或者低延迟都是次要的,所以被设计成不可抢占式内核。
下图给出非抢占式内核调度情况:
![](https://i-blog.csdnimg.cn/blog_migrate/e84d5bcbf9459feb539c3bcff084ef9a.jpeg)
下图给出抢占式内核调度情况:
![](https://i-blog.csdnimg.cn/blog_migrate/073e8b4d79e9370cef75949a8a10df52.jpeg)
对比两个图可以发现:采用抢占式内核调度的情况下,在中断中唤醒一个高优先级任务能够得到很好的响应。
关于抢占式内核还是不可抢占式内核的选择在源码的kernel/Kconfig.preempt有所描述:
config PREEMPT_NONE
bool "No Forced Preemption (Server)"
help
¦ This is the traditional Linux preemption model, geared towards
¦ throughput. It will still provide good latencies most of the
¦ time, but there are no guarantees and occasional longer delays
¦ are possible.
¦ Select this option if you are building a kernel for a server or
¦ scientific/computation system, or if you want to maximize the
¦ raw processing power of the kernel, irrespective of scheduling
¦ latencies.
config PREEMPT
bool "Preemptible Kernel (Low-Latency Desktop)"
depends on !ARCH_NO_PREEMPT
select PREEMPTION
select UNINLINE_SPIN_UNLOCK if !ARCH_INLINE_SPIN_UNLOCK
select PREEMPT_DYNAMIC if HAVE_PREEMPT_DYNAMIC
help
¦ This option reduces the latency of the kernel by making
¦ all kernel code (that is not executing in a critical section)
¦ preemptible. This allows reaction to interactive events by
¦ permitting a low priority process to be preempted involuntarily
¦ even if it is in kernel mode executing a system call and would
¦ otherwise not be about to reach a natural preemption point.
¦ This allows applications to run more 'smoothly' even when the
¦ system is under load, at the cost of slightly lower throughput
¦ and a slight runtime overhead to kernel code.
¦ Select this if you are building a kernel for a desktop or
¦ embedded system with latency requirements in the milliseconds
¦ range.
上面列举了两个编译选项一个是支持内核抢占一个是不支持内核抢占,其实还有PREEMPT_VOLUNTARY和PREEMPT_RT,前者会显式增加一些抢占点,后者用于支持实时性 。
3.重新调度标志和抢占计数器
内核有些路径是