一、处理优先级
内核内部对优先级的处理相当复杂。
1、优先级的内核表示
在用户空间可以通过nice命令设置进程的静态优先级,这在内部会调用nice系统调用。进程的nice值在-20和+19之间(包含)。值越低,表明优先级越高。
内核使用一个简单些的数值范围,从0到139(包含),用来表示内部优先级。同样是值越低,优先级越高。从0到99的范围专供实时进程使用。nice值[-20, +19]映射到范围100到139,如图2-14所示。实时进程的优先级总是比普通进程更高。
下列宏用于在各种不同表示形式之间转换( MAX_RT_PRIO指定实时进程的最大优先级,而MAX_PRIO则是普通进程的最大优先级数值):
linux/sched.h
kernel/sched.c
2、计算优先级
只考虑进程的静态优先级是不够的,还必须考虑下面3个优先级。即动态优先级( task_struct->prio)、普通优先级
( task_struct->normal_prio)和静态优先级( task_struct->static_prio)。这些优先级按有趣的方式彼此关联,下文中会具体讨论。
static_prio是计算的起点。假定它已经设置好,而内核现在想要计算其他优先级。一行代码即可:
p->prio = effective_prio(p);
辅助函数effective_prio执行了下列操作:
kernel/sched.c
首先计算了普通优先级,并保存在normal_priority。这个副效应使得能够用一个函数调用设置两个优先级( prio和normal_prio)。另一个辅助函数rt_prio,会检测普通优先级是否在实时范围中,即是否小于MAX_RT_PRIO。请注意,该检测与调度类无关,它只涉及优先级的数值。
假定在处理普通进程,不涉及实时调度。在这种情况下, normal_prio只是返回静态优先级。结果很简单:所有3个优先级都是同一个值,即静态优先级。
实时进程的情况有所不同。注意普通优先级的计算方法:
kernel/sched.c
普通优先级需要根据普通进程和实时进程进行不同的计算。__normal_prio的计算只适用于普通进程。而实时进程的普通优先级计算,则需要根据其rt_priority设置。由于更高的rt_priority值表示更高的实时优先级,内核内部优先级的表示刚好相反,越低的值表示的优先级越高。因此,实时进程在内核内部的优先级数值,正确的算法是MAX_RT_PRIO - 1 - p->rt_priority。这一次请注意,与effective_prio相比,实时进程的检测不再基于优先级数值,而是通过task_struct中设置的调度策略来检测。
__normal_priority函数只是返回静态优先级:
但还有一个问题:为什么内核在effective_prio中检测实时进程是基于优先级数值,而非task_has_rt_policy?对于临时提高至实时优先级的非实时进程来说,这是必要的,这种情况可能发生在使用实时互斥量( RT-Mutex)时。