linux進程調度

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週期檢查是否搶佔

非實時進程:

相關文章
相關標籤/搜索