閱讀550 返回首頁    go 阿裏雲 go 技術社區[雲棲]


調度子係統2_核心調度器

//	核心調度器
//		當進程決定讓出cpu時調用
//	函數任務:
//		1.禁止內核搶占
//		2.獲取本cpu的rq
//		3.取消為當前進程運行的hrtimer
//		4.獲取隊列鎖
//		5.更新隊列時鍾
//		6.清除當前進程need resched標誌
//		7.如果當前進程為非運行狀態,並且當前非內核搶占路徑
//			7.1 如果當前進程有信號待處理,設置當前進程為就緒狀態
//			7.2 否則進程出隊rq
//		8.如果當前rq沒有可運行進程
//			8.1 通過load balance從其他進程搬進程
//		9.通知調度器類用另一個進程代替當前進程
//		10.通知調度器類選擇下一個可運行進程
//		11.如果下一個運行的進程非當前進程
//			11.1 執行進程切換
//		12.否則釋放隊列鎖
//		13.開啟內核搶占
//		14.如果當前進程被設置need resched,重複1 
1.1 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
	rq = cpu_rq(cpu);
	//當前rq上正在運行的進程
	prev = rq->curr;
	//進程被切換的次數
	switch_count = &prev->nivcsw;

	//取消為當前進程運行的hrtimer
	if (sched_feat(HRTICK))
		hrtick_clear(rq);
	//獲取隊列鎖
	raw_spin_lock_irq(&rq->lock);
	//更新隊列時鍾
	update_rq_clock(rq);
	//清除當前進程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
		{	//進程出隊rq
			deactivate_task(rq, prev, 1);
		}
			
		switch_count = &prev->nvcsw;
	}
	//通知調度器類,即將發生進程切換
	pre_schedule(rq, prev);
	//當前rq沒有可運行進程,通過loadbalance從其他cpu的rq搬進程過來
	if (unlikely(!rq->nr_running))
		idle_balance(cpu, rq);
	//通知調度器類用另一個進程代替當前進程
	put_prev_task(rq, prev);
	//通知調度器類選擇下一個可運行進程
	next = pick_next_task(rq);
	//切換當前進程
	if (likely(prev != next)) {	
		//統計rq切換次數
		rq->nr_switches++;
		rq->curr = next;
		++*switch_count;
		//切換進程上下文
		context_switch(rq, prev, next); 
		//現在已經是另一個進程在運行
		cpu = smp_processor_id();
		rq = cpu_rq(cpu);
	} else
		raw_spin_unlock_irq(&rq->lock);
	//通知調度器類,完成了進程切換
	post_schedule(rq);
	//開啟內核搶占
	preempt_enable_no_resched();
	//如果當前進程需要切換,則再次切換
	if (need_resched())
		goto need_resched;
}

//	通知調度器類,即將進程切換
2.1 static inline void pre_schedule(struct rq *rq, struct task_struct *prev)
{
	if (prev->sched_class->pre_schedule)
		prev->sched_class->pre_schedule(rq, prev);
}

//	通知調度器,完成了進程切換
2.2 static inline void post_schedule(struct rq *rq)
{
	if (rq->post_schedule) {
		unsigned long flags;
		//獲取隊列鎖
		raw_spin_lock_irqsave(&rq->lock, flags);
		if (rq->curr->sched_class->post_schedule)
			rq->curr->sched_class->post_schedule(rq);
		raw_spin_unlock_irqrestore(&rq->lock, flags);
		rq->post_schedule = 0;
	}
}

//	通知調度器類,用另一個進程替換當前進程
3.1 static void put_prev_task(struct rq *rq, struct task_struct *prev)
{
	....
	prev->sched_class->put_prev_task(rq, prev);
}


//	通知調度器類,選擇下一個運行的進程
4.1 static inline struct task_struct *pick_next_task(struct rq *rq)
{
	const struct sched_class *class;
	struct task_struct *p;

	//如果rq中進程數等於cfs中進程數,說明沒有rt進程,由cfs選出下一個運行的進程
	if (likely(rq->nr_running == rq->cfs.nr_running)) {
		p = fair_sched_class.pick_next_task(rq);
		if (likely(p))
			return p;
	}
	//否則由最高優先級的調度類
	class = sched_class_highest;
	for ( ; ; ) {
		//選擇下一個運行進程
		p = class->pick_next_task(rq);
		if (p)
			return p;
		//下一個優先級的調度類
		class = class->next;
	}
}
//	最高優先級調度器類
4.2 #define sched_class_highest (&rt_sched_class)

最後更新:2017-04-03 12:53:45

  上一篇:go 【轉載】DSP看門狗定時器
  下一篇:go 【轉載】ubuntu設置允許遠程登陸