Linux内核之核心调度器

来源:互联网 发布:网络人肉搜索神器 编辑:程序博客网 时间:2024/06/09 23:02

在Linux中内核提供了两个调度器主调度器,周期性调度器

主调度器是直接的, 比如进程打算睡眠或出于其他原因放弃CPU,schedule函数

周期性调度器是通过周期性的机制, 以固定的频率运行, 不时的检测是否有必要,scheduler_tick查看当前进程是否运行太长时间,如果是,将进程的TIF_NEED_RESCHED置位,然后再中断返回时,调用schedule,进行进程切换操作

两个调度器结合起来称为核心调度器

/* * schedule() is the main scheduler function. */asmlinkage void __sched schedule(void){struct task_struct *prev, *next;unsigned long *switch_count;struct rq *rq;int cpu;need_resched://关闭内核抢占preempt_disable();cpu = smp_processor_id();//获得当前cpu的运行队列rq = cpu_rq(cpu);//增加当前quiescent state计数(RCU锁相关)rcu_qsctr_inc(cpu);prev = rq->curr;switch_count = &prev->nivcsw;//释放当前进程的大内核锁release_kernel_lock(prev);need_resched_nonpreemptible:schedule_debug(prev);hrtick_clear(rq);/* * Do the rq-clock update outside the rq lock: *///关闭中断local_irq_disable();update_rq_clock(rq);spin_lock(&rq->lock);//清除当前进程的need_resched标志clear_tsk_need_resched(prev);//如果当前进程不可运行并且在内核态没有被抢占if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {//如果当前进程处于等待信号的状态,就不能把它移出就绪队列,还要把状态设置为就绪状态if (unlikely(signal_pending_state(prev->state, prev)))prev->state = TASK_RUNNING;else//把当前进程移出就绪队列deactivate_task(rq, prev, 1);switch_count = &prev->nvcsw;}#ifdef CONFIG_SMPif (prev->sched_class->pre_schedule)prev->sched_class->pre_schedule(rq, prev);#endifif (unlikely(!rq->nr_running))idle_balance(cpu, rq);//将切换出去的进程插到队尾prev->sched_class->put_prev_task(rq, prev);//挑选下一个最合适的进程执行next = pick_next_task(rq, prev);if (likely(prev != next)) {//更新调度相关信息(时间片)sched_info_switch(prev, next);rq->nr_switches++;rq->curr = next;++*switch_count;//上下文切换context_switch(rq, prev, next); /* unlocks the rq *//* * the context switch might have flipped the stack from under * us, hence refresh the local variables. */cpu = smp_processor_id();rq = cpu_rq(cpu);} elsespin_unlock_irq(&rq->lock);hrtick_set(rq);if (unlikely(reacquire_kernel_lock(current) < 0))goto need_resched_nonpreemptible;preempt_enable_no_resched();if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))goto need_resched;}

/* * This function gets called by the timer code, with HZ frequency. * We call it with interrupts disabled. * * It also gets called by the fork code, when changing the parent's * timeslices. */void scheduler_tick(void){int cpu = smp_processor_id();//获得当前cpu的就绪队列struct rq *rq = cpu_rq(cpu);struct task_struct *curr = rq->curr;sched_clock_tick();spin_lock(&rq->lock);// 更新rq的当前时间戳.即使rq->clock变为当前时间戳update_rq_clock(rq);update_cpu_load(rq);//执行当前运行进程所在调度类的task_tick函数进行周期性调度curr->sched_class->task_tick(rq, curr, 0);spin_unlock(&rq->lock);#ifdef CONFIG_SMP    //当前CPU是否空闲rq->idle_at_tick = idle_cpu(cpu);    //如果到是时候进行周期性负载平衡则触发SCHED_SOFTIRQtrigger_load_balance(rq, cpu);#endif}


0 0