Linux调度器实现 二
接着昨天的论述...
假定虚拟时间由fair_clock,那么fair_clock-wait_runtime,即完全公平调度时间于等待时间的差值来确定进程在树中的排序。Linux调度的信息可以在打开调度器统计宏时,虚拟文件系统的/proc/sched_debug可以详细看到当前调度器细节。
2.1调度器的基本框架:
调度器自身完全不涉及进程的管理,而把工作委托给相应的调度类(sched_class),只有点类似于面向对象编程设计模式的对象的委托代理,每一个进程在某一个时刻只可以属于某一种调度器类,根据调度策略确定。下面我们来阅读Linux源码中进程数据结构和调度器相关的数据成员,以便有一个直观的认识。
{ ..... //前面不相关的略去
int prio, static_prio, normal_prio;
struct list_head run_list;
const struct sched_class *sched_class;
struct sched_entity se;
unsigned int policy;
cpumask_t cpus_allowed;
unsigned int time_slice;
#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
struct sched_info sched_info;
#endif
...
unsigned int rt_priority;
};
- prio和normal_prio属于动态优先级,static_prio属于静态优先级,是进程计算优先级的起点,在进程启动时分配,可以用nice和sched_setscheduler系统调用修改,其它两个优先级根据不同的进程调度策略(policy成员表示)计算得来,即:p->prio=effectiv_prio(p);进程在调度时考虑的优先级为prio,注意:在进程分支时刻,子进程会继承普通优先级(normal_prio);
- run_list和time_slice是循环实时调度器所需要的,不用于完全公平调度器。run_list是一个表头,用于维护包括各个进程的一个运行表,而time_slice则指定进程可使用CPU剩余时间段。
- sched_class表示该进程所属于的调度器类。根据调度策略的不同分为三种:实时调度类rt_sched_class,完全公平调度类fair_sched_class和空闲进程调度类idle_sched_class。调度类之间的层次是单调的,通过一个简单的单向链表连接,rt_sched_class.next = fair_sched_class;fair_sched_class.next = idle_sched_class;idle_sched_class.next = NULL;很显然,实时仅在完全公平进程之前处理,完全公平进程又优于空闲进程;空闲进程只有在CPU空闲时调用。注意这个层次结构在编译时已经建立,没有在运行时动态增加新的调度器类的机制。
- se表示调度实体,调度器一般不直接操作进程,而是处理可调度实体,一个实体由sched_entity的实例表示。task_struct内嵌了该成员,可以通过container_of的方法获取进程实例。
- policy保存了对该进程应用的调度策略。Linux支持5个可能的值: SCHED_NORMAL用于普通进程,通过完全公平调度器来处理。 SCHED_BACH也通过完全公平调度器来处理,用于非交互,CPU使用密集的批处理进程,CPU绝不会抢占CF调度器处理的另一个进程,不会干扰交互式进程。 SCHED_IDLE也通过完全公平调度器来处理,相对权重总是最小,注意SCHED_IDLE不负责调度空闲进程。空闲进程由内核提供单独的机制来完成。 SCHED_RR用于软实时进程,使用循环的方法,由实时调度器类处理。 SCHED_FIFO也用于软实时进程,使用先进先出的机制,由实时调度器类处理。 * rt_policy(int policy)用于判断给出的调度策略属于实时类(SCHED_RR 或SCHED_FIFO),task_has_rt_policy(struct task_struct *p)用于对给定进程判断该特性。
- cpu_allowed是一个位域,在多处理器系统上使用,用来限制进程可以在哪些CPU上运行,可以使用sched_setaffinity系统调用设置该位图。
- sched_info用于调度器统计该进程的相关运行信息。
浙公网安备 33010602011771号