zoukankan      html  css  js  c++  java
  • 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 模式

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

      

  • 相关阅读:
    XML错误信息Referenced file contains errors (http://www.springframework.org/schema/beans/spring-beans-4.0.xsd). For more information, right click on the message in the Problems View ...
    Description Resource Path Location Type Cannot change version of project facet Dynamic Web Module to 2.3.
    maven创建web报错Cannot read lifecycle mapping metadata for artifact org.apache.maven.plugins:maven-compiler-plugin:maven-compiler-plugin:3.5.1:runtime Cause: error in opening zip file
    AJAX跨域
    JavaWeb学习总结(转载)
    JDBC学习笔记
    Java动态代理之JDK实现和CGlib实现
    (转)看懂UML类图
    spring boot配置使用fastjson
    python3下django连接mysql数据库
  • 原文地址:https://www.cnblogs.com/songbingyu/p/3702126.html
Copyright © 2011-2022 走看看