• Linux内核架构读书笔记


    什么是核心调度器?

      参考前面的博文http://www.cnblogs.com/songbingyu/p/3696414.html

      1 周期性调度器

        作用:

      • 管理内核中与整个系统和各个进程的调度相关的统计量
      • 负责当前调度类的周期性调度方法

        kernel/sched.c

     1 /*
     2  * This function gets called by the timer code, with HZ frequency.
     3  * We call it with interrupts disabled.
     4  *
     5  * It also gets called by the fork code, when changing the parent's
     6  * timeslices.
     7  */
     8 void scheduler_tick(void)
     9 {
    10     int cpu = smp_processor_id();
    11     struct rq *rq = cpu_rq(cpu);
    12     struct task_struct *curr = rq->curr;
    13     u64 next_tick = rq->tick_timestamp + TICK_NSEC;
    14 
    15     spin_lock(&rq->lock);
    16     __update_rq_clock(rq);
    17     /*
    18      * Let rq->clock advance by at least TICK_NSEC:
    19      */
    20     if (unlikely(rq->clock < next_tick))
    21         rq->clock = next_tick;
    22     rq->tick_timestamp = rq->clock;
    23     update_cpu_load(rq);
    24         ....

        _update_rq_clock 处理就绪队列时钟更新,本质上增加struct rq 的时间戳

        update_cpu_load 负责更新就绪队列的cpu_load[] 数组,本质上相当与将数组中先前存储的负载值向后移动一个位置,将当前就绪队列的负载值计入数组的第一个位置、、、

        kernel/sched.c

    1     if (curr != rq->idle) /* FIXME: needed? */
    2         curr->sched_class->task_tick(rq, curr);

        task_tick 实现取决与底层的调度器类

        注意: 如果进程应该被重新调度,调度器类会在task_struct中设置TIF_NEED_RESCHED标志,已表示该请求,内核会载接下来的适当时机完成该请求

      2 主调度器

       在内核的许多地方,如果要将CPU 分配给当前活动进程不同的另一个进程,都会直接调用主调度器函数(schedule)

      kernel/sched.c

     1 /*
     2  * schedule() is the main scheduler function.
     3  */
     4 asmlinkage void __sched schedule(void)
     5 {
     6     struct task_struct *prev, *next;
     7     long *switch_count;
     8     struct rq *rq;
     9     int cpu;
    10 
    11 need_resched:
    12     preempt_disable();
    13     cpu = smp_processor_id();
    14     rq = cpu_rq(cpu);
    15     rcu_qsctr_inc(cpu);
    16     prev = rq->curr;
    17     switch_count = &prev->nivcsw;

      

           类似与周期性调度器,内核也利用该时机来更新就绪队列的时钟,并清楚当前运行进程中的重调度标志TIF_NEED_RESCHED

      kernel/sched.c

    1 __update_rq_clock(rq);
    2     spin_lock(&rq->lock);
    3     clear_tsk_need_resched(prev);

      如果当前进程原来处于可中断睡眠状态但现在接受到信号,,那吗它必须再次提升为运行进程,负责相应调度器类的方法使进程停止活动(deactivate_task实质上最终调用sched_class->dequeue_task)

    1 if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
    2         if (unlikely((prev->state & TASK_INTERRUPTIBLE) &&
    3                 unlikely(signal_pending(prev)))) {
    4             prev->state = TASK_RUNNING;
    5         } else {
    6             deactivate_task(rq, prev, 1);
    7         }
    8         switch_count = &prev->nvcsw;
    9     }

      

      put_prev_task同志调度器类当前进程将要被另一个进程代替,不是从就绪队列移除,而是提供一个时机进行一些统计工作

      pick_next_task 选择下一个进程

    1     prev->sched_class->put_prev_task(rq, prev);
    2     next = pick_next_task(rq, prev);

      不见得必然选择一个进程,有可能其他进程都在睡眠

      kernel/sched.c

    1 if (likely(prev != next)) {
    2         rq->nr_switches++;
    3         rq->curr = next;
    4         ++*switch_count;
    5 
    6         context_switch(rq, prev, next); /* unlocks the rq */

      content_switch 一个接口,供访问特定与体系结构的方法

      

      下面代码检测当前的重调度位是否设置,并跳转

    1     if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
    2         goto need_resched;

      注意:上述代码可能载两个上下文中执行  无上下文切换,schedule 末尾直接执行,如果执行上下文切换,在新的上下文执行,所以需要current 和 test_thread_flag 找到当前进程

      3 与fork 交互

      使用fork或其变体建立新进程时候,调度器有机会用sched_fork 挂钩到该进程

      再单处理器上,执行三个操作,初始化新进程与调度相关字段,建立数据结构 确定进程的动态优先级

      kernel/sched.c/sched_fork

        /*
         * Make sure we do not leak PI boosting priority to the child:
         */
        p->prio = current->normal_prio;
        if (!rt_prio(p->prio))
            p->sched_class = &fair_sched_class;

       在使用wake_up_new_task 唤醒新的进程,是调度器与创建逻辑交互的第二时机,内核会调用task_new 函数,将进程加入到相应的就绪队列

      

      4 上下文切换

      content_switch 

      kernel/sched.c

     1 /*
     2  * context_switch - switch to the new MM and the new
     3  * thread's register state.
     4  */
     5 static inline void
     6 context_switch(struct rq *rq, struct task_struct *prev,
     7            struct task_struct *next)
     8 {
     9     struct mm_struct *mm, *oldmm;
    10 
    11     prepare_task_switch(rq, prev, next);
    12     mm = next->mm;
    13     oldmm = prev->active_mm;

      上下文切换调用两个特定与体系结构的的函数

        1 switch_mm

        2 switch_to

      kernel/sched.c

    1     if (unlikely(!mm)) {
    2         next->active_mm = oldmm;
    3         atomic_inc(&oldmm->mm_count);
    4         enter_lazy_tlb(oldmm, next);
    5     } else
    6         switch_mm(oldmm, mm, next);

      entry_lazy_tlb 通知底层结构体系不许要切换虚拟地址空间的用户部分

      

      如果前一进程是内核进程(prev-》mm 为 null ) ,其 active_mm 必须重置为null

      kernel/sched.c

    1     if (unlikely(!prev->mm)) {
    2         prev->active_mm = NULL;
    3         rq->prev_mm = oldmm;
    4     }

      

      最后用switch_to 完成进程切换

      switch_to 之后的代码只有当前进程下一次被选择运行是才会运行

      finish_task_switch 完成一些清理工作

     1     /* Here we just switch the register state and the stack. */
     2     switch_to(prev, next, prev);
     3 
     4     barrier();
     5     /*
     6      * this_rq must be evaluated again because prev may have moved
     7      * CPUs since it called schedule(), thus the 'rq' on its stack
     8      * frame will be invalid.
     9      */
    10     finish_task_switch(this_rq(), prev);

      

    •   switch_to 的复杂之处

      finish_task_switch 特点,调度器可能选择了一个新的进程,但是清理则是针对此前的活动进程

      eg

      

      其实上面只是表达一个意思

      

      在新的进程被再次执行时候,获得上一次运行的是那一个进程

      还没想明白。。。mark

    •   惰性FPU 模式

      浮点寄存器,除非有程序使用,负责不会保存,此外除非有应用程序需要,负责这些寄存器不会恢复

      

  • 相关阅读:
    【2018年11月21日】煤炭行业的估值高度排名
    【2018年11月16日】绩优超跌个股排名
    【2018年11月15日】航空航天与国防行业的估值高度排名
    【2018-11-15】中证1000指数的估值详情
    【11-13】A股主要指数的市盈率(PE)估值高度
    【2018年11月12日】其他化学制品行业的股票估值
    【2018-11-09】中证500指数的估值详情
    【2018年10月29日】食品、饮料与烟草行业的估值高度排名
    2018-10-29 A股主要指数的市盈率(PE)估值高度
    中证500等主要指数的市盈率(PE)估值高度
  • 原文地址:https://www.cnblogs.com/songbingyu/p/3702126.html
Copyright © 2020-2023  润新知