Linux内核进程调度机制详解(2)

repeat_schedule:
next = idle_task(this_cpu);
c = -1000;
/*遍历进程就绪队列,如果该进程能够进行调度(对于SMP来说就是判断当前CPU未被占用能够执行这个进程,对于非SMP系统则为1),则计算该进程的优先级,如果优先级大于当前进程,则next指针指向新的进程,循环直到找到优先级最大的那个进程*/
list_for_each(tmp, &runqueue_head) {
        p = list_entry(tmp, struct task_struct, run_list);
        if (can_schedule(p, this_cpu)) {
               int weight = goodness(p, this_cpu, prev->active_mm);
               if (weight > c)
                      c = weight, next = p;
        }
}

/* 判断是否需要重新计算每个进程的时间片,判断的依据是所有正准备进行调度的进程时间片耗尽,这时,就需要对就绪队列中的每一个进程都重新计算时间片,然后返回前面的调度过程,重新在就绪队列当中查找优先级最高的进程执行调度。 */
if (unlikely(!c)) {
        struct task_struct *p;

spin_unlock_irq(&runqueue_lock);
        read_lock(&tasklist_lock);
        for_each_task(p)
               p->counter = (p->counter >> 1) + NICE_TO_TICKS(p->nice);
        read_unlock(&tasklist_lock);
        spin_lock_irq(&runqueue_lock);
        goto repeat_schedule;
}

/*CPU私有调度数据中记录当前进程的指针,并且将当前进程与CPU绑定,如果待调度进程与前面一个进程属于同一个进程,则不需要调度,直接返回。*/
sched_data->curr = next;
task_set_cpu(next, this_cpu);
spin_unlock_irq(&runqueue_lock);

if (unlikely(prev == next)) {
        /* We won't go through the normal tail, so do this by hand */
        prev->policy &= ~SCHED_YIELD;
        goto same_process;
}
/*全局统计进程上下文切换次数*/
kstat.context_swtch++;
/*如果后进程的mm为0 (未分配页),则检查是否被在被激活的页里(active_mm),否则换页。令后进程记录前进程激活页的信息,将前进程的active_mm中的 mm_count值加一。将cpu_tlbstate[cpu].state改为 TLBSTATE_LAZY(采用lazy模式) 如果后进程的mm不为0(已分配页),但尚未激活,换页。切换mm(switch_mm)。 如果前进程的mm 为0(已失效) ,将其激活记录置空,将mm结构引用数减一,删除该页。 */
prepare_to_switch();
{
        struct mm_struct *mm = next->mm;
        struct mm_struct *oldmm = prev->active_mm;
        if (!mm) {
               BUG_ON(next->active_mm);
               next->active_mm = oldmm;
               atomic_inc(&oldmm->mm_count);
               enter_lazy_tlb(oldmm, next, this_cpu);
        } else {
               BUG_ON(next->active_mm != mm);
               switch_mm(oldmm, mm, next, this_cpu);
        }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/22790.html