等待佇列
sleep相關函式將程序的狀態設定為非執行態,在下一次排程來時,將在schedule函式中將本程序從執行佇列中移除。sleep函式將程序加入等待佇列,然後呼叫schedule函式選擇並重新開始另乙個程式的執行。當呼叫wake_up類函式將程序喚醒時,wake_up類函式將程序加入執行佇列中,排程程式重新從sleep函式中下一條沒有執行的指令開始執行。
sleep類函式都呼叫sleep_on_common函式實現,只是傳入的引數有別。
static long __sched sleep_on_common(wait_queue_head_t *q, int state, long timeout)
static inline void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p)
我們看喚醒函式,default_wake_function最終呼叫函式try_to_wake_up
/*** * try_to_wake_up - wake up a thread * @p: the to-be-woken-up thread * @state: the mask of task states that can be woken * @sync: do a synchronous wakeup? * * put it on the run-queue if it's not already there. the "current" * thread is always on the run-queue (except when the actual * re-schedule is in progress), and as such you're allowed to do * the ******r "current->state = task_running" to mark yourself * runnable without the overhead of this. * * returns failure only if the task is already active. */ static int try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) } } #endif /* config_schedstats */ out_activate: #endif /* config_smp */ /*下面為設定相關計數變數*/ schedstat_inc(rq, field)(p, se.nr_wakeups); if (wake_flags & wf_sync) schedstat_inc(p, se.nr_wakeups_sync); if (orig_cpu != cpu) schedstat_inc(p, se.nr_wakeups_migrate); if (cpu == this_cpu) schedstat_inc(p, se.nr_wakeups_local); else schedstat_inc(p, se.nr_wakeups_remote); /*將程序移動到對應排程類的執行佇列*/ activate_task(rq, p, 1); success = 1; /* * only attribute actual wakeups done by this task. */ if (!in_interrupt()) out_running: trace_sched_wakeup(rq, p, success); /*用以決定乙個task是否可以中斷目前正在 運作的task,取得執行權.*/ check_preempt_curr(rq, p, wake_flags); p->state = task_running; #ifdef config_smp if (p->sched_class->task_wake_up) p->sched_class->task_wake_up(rq, p); if (unlikely(rq->idle_stamp)) #endif out: task_rq_unlock(rq, &flags); put_cpu(); return success; }
所有的wake_up類函式都最終呼叫__wake_up_common函式實現
static void __wake_up_common(wait_queue_head_t *q, unsigned int mode, int nr_exclusive, int wake_flags, void *key) }
wait_event方式
考慮到sleep_on類函式在以下條件中不能使用,那就是必須測試條件並且當條件還沒喲得到驗證時又緊接著讓進城去睡眠;為實現這樣的功能,核心採用wait_event的方式實現。
#define __wait_event(wq, condition) \ do /*當程序被喚醒時繼續如下執行*/ \ finish_wait(&wq, &__wait); \ } while (0)
當下一次排程到來時,排程程式把設定為非執行的當前程序從執行佇列裡面刪除,而程序被wake_up類函式喚醒時,wake_up類函式將其加入執行佇列,繼續執行上面沒有執行完成的wait_event函式(執行finish_wait函式),finish_wait函式將其從等待佇列中刪除。
linux核心程序排程系列之排程概述
多工作業系統分為非搶占式多工和搶占式多工。linux採用的是搶占式多工的模式,這就意味著程序對cpu的占用時間是由作業系統決定的,跟具體的說,由作業系統的程序排程程式所決定的,這個章節就介紹關於程序的排程策略。一 排程策略 1 其實程序的排程策略和程序的型別有關 第一種分配方法 cpu消耗型和i o...
Linux核心 程序排程
搶占式多工 由排程程式來決定什麼時間停止乙個程序的執行 程序的時間片 分配給每個可執行程序的處理器時間段 o 1 排程程式 反轉樓梯最後期限排程演算法 完全公平排程演算法 i o消耗型和處理器消耗型程序 i o消耗型程序 大部分時間用來提交i o請求或等待i o請求 處理器消耗型程序 把時間大部分用...
深入Linux核心 一 程序排程
1.交換式程序interactive processes 互動式程序是經常與使用者進行互動,因此需要花很多的時間等待鍵盤和滑鼠操作,當接受輸入後,程序必須被很快喚醒,不然就會出現系統反應遲鈍。典型的互動式程式是shell命令 文字編輯和影象應用程式 2.批處理程序batch process 不必與使...