Linux内核之核心调度器

在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_SMP
	if (prev->sched_class->pre_schedule)
		prev->sched_class->pre_schedule(rq, prev);
#endif

	if (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);
	} else
		spin_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_SOFTIRQ
	trigger_load_balance(rq, cpu);
#endif
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值