多处理器SMP系统结构--SMP结构中的进程调度

多核进程调度中,相关task_struct 结构中代表进程与CPU之间关系的变量

struct task_struct{

    ...

    int has_cpu, processor;

    unsigned long cpus_allowed;

    ...

}

has_cpu:表示当前进程在CPU上正在运行;

processor:表示在哪个CPU上运行;

cpus_allowed:一个位图变量,其中一位,置1,表示允许这个进程接受调度在置1编号的CPU上运行。

系统中的进程调度

当一个CPU通过schedule()从系统的就绪队列中挑选一个进程作为运行的下一个进程next,其task_struct结构中的has_cpu字段置成1,并将processor设置成该CPU的逻辑编号。进行任务切换也就是进程状态、内存、寄存器、堆栈的切换,以及TLB的是否刷新等等。

asmlinkage void schedule(void)
{
    ...
    /*                            
     * 1.Default process to select..
     */                           
    next = idle_task(this_cpu);   
    ...
    /* 
     * 2.从运行队列中找到能够调度运行的进程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;                           
    ____}                                                       
    }
    ...
    /*
     * 3.如果是多核处理器,则更新进程 task_struct 中的标志
    */
    next->has_cpu = 1
    next->processor = this_cpu;
    ...
    /*
     * 4. prepare_to_switch()
     */
____{                                             
________struct mm_struct *mm = next->mm;          
________struct mm_struct *oldmm = prev->active_mm;
________if (!mm) {    /* 如果是内核线程*/
____________if (next->active_mm) BUG();           
____________next->active_mm = oldmm;              
____________atomic_inc(&oldmm->mm_count);         
____________enter_lazy_tlb(oldmm, next, this_cpu);/*暂时先不更新TLB*/
________} else {    /*如果是用户空间线程*/
____________if (next->active_mm != mm) BUG();     
____________switch_mm(oldmm, mm, next, this_cpu);/**/
________}                                         
                                                  
________if (!prev->mm) {                          
____________prev->active_mm = NULL;               
____________mmdrop(oldmm);                        
________}                                         
____}
    ...
    /*
     * 5.                                             
____ * This just switches the register state and the
____ * stack.                                       
____ */                                             
____switch_to(prev, next, prev);
    /*
     * 6. 尝试再次运行:在剩下的CPU中,寻找能替换的进程,也就是“运行优先级”最低的进程。 
     */
______schedule_tail(prev);                          
    ...
}

根据在CPU中运行的prev进程与next进程的不同,所处理细节也不同。prev进程发生切换的方式主要如下:

  1. 自愿礼让: (prev->policy &=  ~SCHED_YIELD) && (prev->state = TASK_RUNNING)
  2. 被剥夺: (prev->policy  & SCHED_YIELD == FALSE) && (prev->state = TASK_RUNNING)

2.被剥夺再次尝试运行:reschedule_idle()

2.1 首先尝试在当前CPU再次运行

        can_schedule(p, p->processor)

2.2 如果不能在当前CPU运行,则考察系统中所有CPU。如果找到能运行的CPU,当前这个CPU上运行的进程为被剥夺的候选对象。找出所有可被剥夺的所有候选对象中最合适的那个,然后替换执行。

被替换进程最合适的标准:运行时间最长,资格最低的进程。

你可能感兴趣的:(linux)