天天看點

Linux排程-周期性排程器

很早以前有一個問題:搞單片機的時候,在不做響應任何中斷的前提下,任何一個子產品代碼跑一個死循環,機器一定會卡死。但是到了接觸linux之後,發現不論是在核心中還是使用者層代碼中,while(1)把機器搞當機這樣的操作完全失效了,這是為什麼?

原來,這是周期性排程器的功勞,前提核心是搶占式核心

在系統時鐘中斷來之後,在中斷處理函數中會通過tick_periodic最終調到scheduler_tick,也就是一個"滴答"會調用一次這個函數,看下實作:

void scheduler_tick(void)
{
	int cpu = smp_processor_id();
	struct rq *rq = cpu_rq(cpu);
	struct task_struct *curr = rq->curr;
	struct rq_flags rf;

	sched_clock_tick();

	rq_lock(rq, &rf);

	walt_set_window_start(rq, &rf);
	walt_update_task_ravg(rq->curr, rq, TASK_UPDATE,
			walt_ktime_clock(), 0);
	update_rq_clock(rq);
	curr->sched_class->task_tick(rq, curr, 0);


	rq_unlock(rq, &rf);

}
           

這個函數主要就是更新一些統計量例如rq的時鐘計數、cpu負載等,重點在curr->sched_class->task_tick(rq, curr, 0)會去調用目前程序所在排程類的task_tick方法來決定目前程序是不是應該被排程(真正的排程不在這裡是以隻是決定)。

例如rt:

static void task_tick_rt(struct rq *rq, struct task_struct *p, int queued)
{
......

	if (--p->rt.time_slice) //如果時間片用完了,就該排程了
		return;
......
    //加到隊尾,設定TIF_NEED_RESCHED
	for_each_sched_rt_entity(rt_se) {
		if (rt_se->run_list.prev != rt_se->run_list.next) {
			requeue_task_rt(rq, p, 0);
			resched_curr(rq);
			return;
		}
	}
}
           

又比如cfs:

task_tick_fair--->entity_tick--->check_preempt_tick:
check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
{
	unsigned long ideal_runtime, delta_exec;
	struct sched_entity *se;
	s64 delta;

	ideal_runtime = sched_slice(cfs_rq, curr);
        //是不是運作足夠長時間了
	delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime;
	if (delta_exec > ideal_runtime) {
		resched_curr(rq_of(cfs_rq));
		/*
		 * The current task ran long enough, ensure it doesn't get
		 * re-elected due to buddy favours.
		 */
		clear_buddies(cfs_rq, curr);
		return;
	}
        ......
        //是不是有更可憐(遭受更多不公平)的程序需要被執行
	se = __pick_first_entity(cfs_rq);
	delta = curr->vruntime - se->vruntime;

	if (delta < 0)
		return;

	if (delta > ideal_runtime)
		resched_curr(rq_of(cfs_rq));
}
           

如上兩個排程類對task_tick的實作,當達到一定的條件時,都會為目前程序調用resched_curr設定TIF_NEED_RESCHED标志,一旦從中斷傳回核心空間或者從中斷傳回使用者空間時,都會檢查該标志進而隐式地調用schedule搶占目前程序。在不關中斷和進制搶占的時候,while(1);這種操作會先是被中斷打斷,在中斷傳回時可能就會被其他程序搶占。

繼續閱讀