CFS调度:
新进程创建会调用到do_fork
-->wake_up_new_task
-->activate_task(rq, p, 0);
-->enqueue_task(rq, p, flags); // 入就绪队列
-->p->sched_class->enqueue_task(rq, p, flags);
-->check_preempt_curr(rq, p, WF_FORK); // 检查是否可抢占当前进程
对于CFS调度:会调用到fair_sched_class.enqueue_task = enqueue_task_fair
static void
enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
{
struct cfs_rq *cfs_rq;
struct sched_entity *se = &p->se;
for_each_sched_entity(se) {
if (se->on_rq) // 有父进程在队列上,退出for;没有就将该进程以及其父进程都入就绪队列cfs_rq
break;
cfs_rq = cfs_rq_of(se); //得到就绪队列
enqueue_entity(cfs_rq, se, flags);
flags = ENQUEUE_WAKEUP;
}
for_each_sched_entity(se) {
struct cfs_rq *cfs_rq = cfs_rq_of(se);
update_cfs_load(cfs_rq, 0);
update_cfs_shares(cfs_rq);
}
hrtick_update(rq);
}
static void
enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
{
/* do_fork
* Update the normalized vruntime before updating min_vruntime
* through callig update_curr().
*/
if (!(flags & ENQUEUE_WAKEUP) || (flags & ENQUEUE_WAKING))
se->vruntime += cfs_rq->min_vruntime; // 新创建的进程而非唤醒的进程,赋值最小的min_vruntime
/*
* Update run-time statistics of the 'current'.
*/
update_curr(cfs_rq); // 根据进程休眠时间更新delta
update_cfs_load(cfs_rq, 0);
account_entity_enqueue(cfs_rq, se); // 计算进程的权重
update_cfs_shares(cfs_rq);
if (flags & ENQUEUE_WAKEUP) { // 如果是被唤醒的进程,对vruntime值在min_vruntime的基础上给予一定补偿
place_entity(cfs_rq, se, 0);
enqueue_sleeper(cfs_rq, se);
}
update_stats_enqueue(cfs_rq, se);
check_spread(cfs_rq, se);
if (se != cfs_rq->curr)
__enqueue_entity(cfs_rq, se); // 将调度实体加入红黑树
se->on_rq = 1;
if (cfs_rq->nr_running == 1)
list_add_leaf_cfs_rq(cfs_rq);
}
static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
struct rb_node **link = &cfs_rq->tasks_timeline.rb_node;
struct rb_node *parent = NULL;
struct sched_entity *entry;
s64 key = entity_key(cfs_rq, se);
int leftmost = 1;
/*
* Find the right place in the rbtree:
*/
while (*link) {
parent = *link;
entry = rb_entry(parent, struct sched_entity, run_node);
/*
* We dont care about collisions. Nodes with
* the same key stay together.
*/
if (key < entity_key(cfs_rq, entry)) {
link = &parent->rb_left;
} else {
link = &parent->rb_right;
leftmost = 0;
}
}
/*
* Maintain a cache of leftmost tree entries (it is frequently
* used):
*/
if (leftmost)
cfs_rq->rb_leftmost = &se->run_node;
rb_link_node(&se->run_node, parent, link);
rb_insert_color(&se->run_node, &cfs_rq->tasks_timeline);
}
对于实时进程:
enqueue_task_rt(struct rq *rq, struct task_struct *p, int flags)
{
struct sched_rt_entity *rt_se = &p->rt;
if (flags & ENQUEUE_WAKEUP)
rt_se->timeout = 0;
enqueue_rt_entity(rt_se, flags & ENQUEUE_HEAD);
if (!task_current(rq, p) && p->rt.nr_cpus_allowed > 1)
enqueue_pushable_task(rq, p);
}
static void enqueue_rt_entity(struct sched_rt_entity *rt_se, bool head)
{
dequeue_rt_stack(rt_se); // 将该进程的所以父进程移除就绪队列
for_each_sched_rt_entity(rt_se)
__enqueue_rt_entity(rt_se, head);
}
check_preempt_curr(rq, p, WF_FORK):调用调度类里面的check_preempt_curr函数
实时进程:
1、优先级比当前进程高:抢占-->schedule()
2、优先级与当前进程相同:是否有其他CPU可以迁移,迁移
3、同一cpu核下同优先级未抢占,下一次tick周期检查是否抢占
非实时进程: