CFS調度:node
新進程建立會調用到do_fork函數
-->wake_up_new_taskspa
-->activate_task(rq, p, 0);code
-->enqueue_task(rq, p, flags); // 入就緒隊列orm
-->p->sched_class->enqueue_task(rq, p, flags);blog
-->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); }
對於實時進程:get
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函數it
實時進程:
一、優先級比當前進程高:搶佔-->schedule()
二、優先級與當前進程相同:是否有其餘CPU能夠遷移,遷移
三、同一cpu核下同優先級未搶佔,下一次tick週期檢查是否搶佔
非實時進程: