Linux内核深度解析
上QQ阅读APP看书,第一时间看更新

2.9.4 实时调度类的处理器负载均衡

实时调度类的处理器负载均衡和限期调度类相似,如图2.41所示。调度器选择下一个实时进程时,如果当前处理器的实时运行队列中的进程的最高调度优先级比当前正在执行的进程的调度优先级低,将会试图从实时进程超载的处理器把可推送实时进程拉过来。

图2.41 实时调度类的处理器负载均衡

实时进程超载的定义如下。

(1)实时运行队列至少有两个实时进程。

(2)至少有一个可推送实时进程。

可推送实时进程是指绑定到多个处理器的实时进程,可以在处理器之间迁移。

函数pull_rt_task负责从实时进程超载的处理器把可推送实时进程拉过来,其代码如下:

    kernel/sched/rt.c
    1   static void pull_rt_task(struct rq *this_rq)
    2   {
    3    int this_cpu = this_rq->cpu, cpu;
    4    bool resched = false;
    5    struct task_struct *p;
    6    struct rq *src_rq;
    7
    8   if (likely(! rt_overloaded(this_rq)))
    9        return;
    10
    11  for_each_cpu(cpu, this_rq->rd->rto_mask) {
    12       if (this_cpu == cpu)
    13             continue;
    14
    15       src_rq = cpu_rq(cpu);
    16
    17       if (src_rq->rt.highest_prio.next >=
    18          this_rq->rt.highest_prio.curr)
    19             continue;
    20
    21       double_lock_balance(this_rq, src_rq);
    22
    23       p = pick_highest_pushable_task(src_rq, this_cpu);
    24
    25       if (p && (p->prio < this_rq->rt.highest_prio.curr)) {
    26             if (p->prio < src_rq->curr->prio)
    27                  goto skip;
    28
    29             resched = true;
    30
    31             deactivate_task(src_rq, p, 0);
    32             set_task_cpu(p, this_cpu);
    33             activate_task(this_rq, p, 0);
    34       }
    35  skip:
    36       double_unlock_balance(this_rq, src_rq);
    37  }
    38
    39  if (resched)
    40       resched_curr(this_rq);
    41  }

第8行代码,如果不存在实时进程超载的处理器,那么不需要处理。

第11行代码,针对每个实时进程超载的处理器t,处理如下。

1)第17~19行代码,如果处理器t上可推送实时进程的第二高调度优先级比当前处理器上实时进程的最高调度优先级高(数值越大,优先级越低),那么可以考虑拉实时进程过来,否则不用考虑。

2)第23行代码,在处理器t上选择一个调度优先级最高、处于就绪状态并且绑定的处理器集合包含当前处理器的实时进程。

3)第25行代码,如果目标进程的调度优先级比当前处理器上实时进程的最高调度优先级高,处理如下。

❑ 第26行和第27行代码,如果目标进程的调度优先级比处理器t正在执行的进程的调度优先级高,那么不要把目标进程拉过来。这种情况下目标进程正在被唤醒,还没机会调度。

❑ 第31~33行代码,当前处理器把目标进程拉过来。