前面两篇文章从原理角度分析了进程的调度,本文将从具体的源码出发,分析与进程进程调度密切相关的几个函数。
1.时间片的分配:task_timeslice()
正如我们所知的那样,进程的时间片与进程的静态优先级有直接的关系。从代码中可以看到,根据进程静态优先级static_prio与NICE_TO_PRIO(0)的大小关系,进程时间片的分配可以分为两条路线。以下代码如无特别说明均位于linux/kernel/sched.c下。
1 | static unsigned int task_timeslice(task_t *p) |
3 | if (p->static_prio < NICE_TO_PRIO(0)) return SCALE_PRIO(DEF_TIMESLICE*4, p->static_prio); |
5 | return SCALE_PRIO(DEF_TIMESLICE, p->static_prio); |
NICE_TO_PRIO以及PRIO_TO_NICE宏的作用将进行nice值和进程静态优先级之间的转换。nice也用来表示进程的静态优先级,只不过它与静态优先级的大小范围不同,因此可以将nice看作是static_prio的缩影。
1 | #define MAX_USER_RT_PRIO 100 |
2 | #define MAX_RT_PRIO MAX_USER_RT_PRIO |
3 | #define NICE_TO_PRIO(nice) (MAX_RT_PRIO + (nice) + 20) |
4 | #define PRIO_TO_NICE(prio) ((prio) - MAX_RT_PRIO - 20) |
目前我们已经知道普通进程的静态优先级大小范围是100到139,因此从上面的一些列宏可以得知,nice的取值范围为-20到19。
因此,NICE_TO_PRIO(0)取值为120,也就是说进程时间片分配的两条路线是根据静态优先级120进行划分的。从SCALE_PRIO宏的定义我们可以看到,该宏的作用是取两个数值(具体应该是时间片)的最大者。
1 | #define MAX_PRIO (MAX_RT_PRIO + 40) |
2 | #define USER_PRIO(p) ((p)-MAX_RT_PRIO) |
3 | #define MAX_USER_PRIO (USER_PRIO(MAX_PRIO)) |
4 | #define DEF_TIMESLICE (100 * HZ / 1000) |
5 | #define MIN_TIMESLICE max(5 * HZ / 1000, 1) |
6 | # define HZ 1000 //位于linux/include/asm-i386/param.h |
7 | #define SCALE_PRIO(x, prio) / |
8 | max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO/2), MIN_TIMESLICE) |
从上面的宏定义可知,(MAX_USER_PRIO/2)为20。当进程静态优先级小于120时,x的值为DEF_TIMESLICE*4,具体即为400ms;否则x为100ms。因此对于SCALE_PRIO宏可以用下面的公式来表达:
静态优先级<120,基本时间片=max((140-静态优先级)*20, MIN_TIMESLICE)
静态优先级>=120,基本时间片=max((140-静态优先级)*5, MIN_TIMESLICE)
其中MIN_TIMESLICE为系统所规定的最小时间片大小。
2.对可运行队列的操作
在优先级数组结构prio_array中,数组queue用来表示每个优先级所形成的可运行进程队列,而且过期进程和活动进程分别对应这样一个数组。