1. 调用时机
一般会在时钟中断时被调用,作用有:
剥夺时间片耗完的进程的CPU使用权,当然具体细节上没这么简单;进行定时的CPU间负载均衡处理;
2. 大致流程
idle进程(swapper进程)的处理。
idle进程没有时间片可言,主要思路是如果当前逻辑CPU的可执行队里已有进程,应该尽快调度。
这里所指的调度还是延时调度,也就是设置TIF_NEED_RESCHED,
还会有些强制调度之类的处理,细节暂未研究;
实时进程的处理。
在这版本的源码中,没有调度类的概念,实时进程和普通进程是放在相同的可执行队列的。
实时进程的调度状况:
如果可执行的话,会一直停留在active队列,
优先级比所有普通进程高,
因此如果实时进程没有阻塞,同一逻辑CPU中的普通进程没机会运行;
SCHED_RR类型的实时进程在时间片消耗完后,会被放到active队列的末尾,
并且设置TIF_NEED_RESCHED位,
因此拥有不小于当前优先级的其他实时进程会被调度到;
SCHED_FIFO类型的实时进程,就真的除非被更高优先级的实时进程抢占,
时钟中断这边并不能让它们让出CPU;
交互式进程的处理
当时间片用完时,
设置TIF_NEED_RESCHED位;
但当其比expired队列所有进程优先级都高时,
并不放入expired队列中,而是重新放入active队列中;
这是对交互式进程的一种优待处理;
当时间片未用完时,
交互式进程的时间片会被细分为粒度,当运行完一个粒度后,
就需要重新调度,也就是设置TIF_NEED_RESCHED位;
这是对交互式进程的一种削弱,毕竟地位没有实时进程高;
普通非交互式进程的处理
当时间片用完时,
设置TIF_NEED_RESCHED位,并放入到expired队列中;
当时间片未用完时,不作任何操作;
定时负载均衡
在整个函数结束之前执行的一步,对各个CPU进行负载均衡处理。
具体有点复杂,会在load_balance()的文章进行大致介绍;
3. 源码注释
void scheduler_tick(void)
{
int cpu
= smp_processor_id();
runqueue_t
*rq
= this_rq();
task_t
*p
= current
;
rq
->timestamp_last_tick
= sched_clock();
if (p
== rq
->idle
) {
if (wake_priority_sleeper(rq
))
goto out
;
rebalance_tick(cpu
, rq
, SCHED_IDLE
);
return;
}
if (p
->array
!= rq
->active
) {
set_tsk_need_resched(p
);
goto out
;
}
spin_lock(&rq
->lock
);
if (rt_task(p
)) {
if ((p
->policy
== SCHED_RR
) && !--p
->time_slice
) {
p
->time_slice
= task_timeslice(p
);
p
->first_time_slice
= 0;
set_tsk_need_resched(p
);
requeue_task(p
, rq
->active
);
}
goto out_unlock
;
}
if (!--p
->time_slice
) {
dequeue_task(p
, rq
->active
);
set_tsk_need_resched(p
);
p
->prio
= effective_prio(p
);
p
->time_slice
= task_timeslice(p
);
p
->first_time_slice
= 0;
if (!rq
->expired_timestamp
)
rq
->expired_timestamp
= jiffies
;
if (!TASK_INTERACTIVE(p
) || EXPIRED_STARVING(rq
)) {
enqueue_task(p
, rq
->expired
);
if (p
->static_prio
< rq
->best_expired_prio
)
rq
->best_expired_prio
= p
->static_prio
;
}
else
enqueue_task(p
, rq
->active
);
}
else {
if (TASK_INTERACTIVE(p
) && !((task_timeslice(p
) -
p
->time_slice
) % TIMESLICE_GRANULARITY(p
)) &&
(p
->time_slice
>= TIMESLICE_GRANULARITY(p
)) &&
(p
->array
== rq
->active
)) {
requeue_task(p
, rq
->active
);
set_tsk_need_resched(p
);
}
}
out_unlock
:
spin_unlock(&rq
->lock
);
out
:
rebalance_tick(cpu
, rq
, NOT_IDLE
);
}
参考
《深入理解linux内核》
baoyou.xie Linux 2.6.12代码注释