聊完了调度的具体逻辑与时间分配之后,我们再来简单聊一下调度时机,即调度这件事情在什么情况下会发生。O(n) 的调度主要发生在如下场景中:
进程主动发起调度,搜索内核代码会发现大量的地方调用了 schedule()
方法
timer 发现当前进程已经耗尽了自己的时间,触发调度。代码如下:
/* file: kernel/timer.c */
void update_process_times(int user_tick) {
struct task_struct *p = current;
int cpu = smp_processor_id(), system = user_tick ^ 1;
update_one_process(p, user_tick, system, cpu);
if (p->pid) {
/* 运行时间耗尽,设置调度标记 */
if (--p->counter <= 0) {
p->counter = 0;
p->need_resched = 1;
}
if (p->nice > 0)
kstat.per_cpu_nice[cpu] += user_tick;
else
kstat.per_cpu_user[cpu] += user_tick;
kstat.per_cpu_system[cpu] += system;
} else if (local_bh_count(cpu) || local_irq_count(cpu) > 1)
kstat.per_cpu_system[cpu] += system;
}
在定时器中不会直接触发调度,而是设置任务的调度位: p->need_resched = 1;
, 系统在下一轮调度中才会做对应的处理。
系统通过 fork()
创建新任务的时候,新任务的产生会导致系统产生调度需求。
还有很多其它的情况会引发调度,这里不再一一列举了。