1 简介
(1)调度程序工作
1)将哪个投入运行
2)何时运行及运行多长时间
(2)I/O消耗型和处理器消耗型
I/O消耗型:大部分时间处理IO请求
处理器消耗型:大部分时间在执行代码
(3)优先级
两种:
1)nice值:范围是-20~+19,值越大优先级越低
2)实时优先级:范围是0~99,值越大优先级越高。
任何实时进程的优先级大于普通进程
(4)完全公平调度(Completely Fair Scheduler,CFS)
理念:每个进程获得1/n的处理能力
做法:每个进程运行一段时间、循环轮转、选择运行最少的进程作为下一个进程
2 调度器类
目的是将调度器模块化,目前有deadline调度器 、实时调度器、完全公平调度器 、idle task。
调度器主要入口schedule(),调用pick_next_task(),按优先级从高到低,检查每个调取器中的进程。
static inline struct task_struct *
pick_next_task(struct rq *rq)
{
const struct sched_class *class;
struct task_struct *p;
if (likely(rq->nr_running == rq->cfs.nr_running)) {//CFS
p = fair_sched_class.pick_next_task(rq);
if (likely(p))
return p;
}
class = sched_class_highest;
for ( ; ; ) {
p = class->pick_next_task(rq);
if (p)
return p;
class = class->next;
}
}
3 CFS调度实现
3.1 时间
通过update_curr()实现了时间记账功能,更新vruntime。
注:
(1)分配给进程的时间 = 总的cpu时间 * 进程的权重/就绪队列(runqueue)所有进程权重之和
(2)nice值为0的进程的虚拟时间和实际时间是相等的
3.2 进程选择
(1)选择任务
选择具有最小的vruntime运行。CFS使用红黑树组织进程队列,并将最小的vruntime缓存在rb_leftmost字段中。__pick_next_entity选择最左边的进程
static struct sched_entity *__pick_next_entity(struct cfs_rq *cfs_rq)
{
struct rb_node *left = cfs_rq->rb_leftmost;
if (!left)
return NULL;
return rb_entry(left, struct sched_entity, run_node);
}
(2)加入与删除进程
加入——enqueue_entity(),更新统计信息,并调用__enqueue_entity(),将进程插入到红黑树中。
删除——dequeue_entity(),从红黑树中删除进程
3.3 抢占
(1)用户抢占发生情况
1)从系统调用返回用户空间
2)从中断(异常)处理程序返回用户空间。
(2)内核抢占发生情况
条件:没有持有锁,内核就可以抢占,preemt_count记录使用锁情况。
中断返回时,若need_resched被设置,若preemt_count为0,抢占;若不为0,直接返回。
发生情况:
1)中断处理程序正在执行,且返回内核空间之前
2)内核代码再一次具有可抢占的时候
3)内核任务中显示地调用schedule()
4)内核中的任务阻塞