• linux进程调度


    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周期检查是否抢占

    非实时进程:

  • 相关阅读:
    UML类图的关系
    软工视频总结
    面向对象——(1)概述
    软件工程——整体把握
    白盒测试中的逻辑覆盖
    机房收费调试问题(二)
    机房收费调试问题(一)
    如何将ER图转换成关系模式集
    机房收费之感想与收获
    【linux】U盘安装启动出现press the enter key to begin the installation process 就不动弹了
  • 原文地址:https://www.cnblogs.com/zhu-g5may/p/11374164.html
Copyright © 2020-2023  润新知