RT 1.這裡解釋幾個主要的子函數,首先是task_timeslice,重新計算時間片。首先介紹一下基本時間片的概念。 靜態優先順序本質上決定了進程的基本時間片,即進程用完了以前的時間片時,系統分配給進程的時間片長度。靜態優先順序和基本時間片的關係用下列公式確定: 如你所見,靜態優先順序越高(其值越小), ...
RT
/** * 遞減當前進程的時間片計數器,並檢查是否已經用完時間片。 * 由於進程的調度類型不同,函數所執行的操作也有很大差別。 */ /* 如果是實時進程,就進一步根據是FIFO還是RR類型的實時進程 */ if (rt_task(p)) { /** * 對SCHED_RR類型(時間片輪轉)的實時進程,需要遞減它的時間片。 * 對SCHED_FIFO類型(先進先出)的實時進程,什麼都不做, * 退出。在這種情況下, * current進程不可能被比其優先順序低或其優先順序相等的進程所搶占, * 因此維持當前進程的最新時間片計數器是沒有意義的。 */ if ((p->policy == SCHED_RR) && !--p->time_slice) { /** * 對SCHED_RR類型的實時進程,如果它的時間片已經用完, * 就執行此下動作,以達到搶占當前進程的目的。 * 如果必要的話,就儘快搶占。 */ /* 重新計算它的時間片,它根據進程的靜態優先順序來計算它的時間片。 */ p->time_slice = task_timeslice(p); /** * 該標誌被fork常式中的copy_process設置, * 直到這裡,說明進程一定不是第一次運行了, * 它已經用完了一次它的時間片,將first_time_slice置為0. * 這樣,它即使退出,也不會將剩餘的時間片還給父進程了。 */ p->first_time_slice = 0; /** * 設置調度標誌,以達到儘快搶占的目的。 * 該標誌強制調用schedule函數,以便current指向的進程能 * 被另外一個有相同優先順序(或更高優先順序)的實時進程(如果有)所取代。 */ set_tsk_need_resched(p); /* put it at the end of the queue: */ /** * 將實時進程放到隊列末尾。這樣,如此鏈表中還有其他同優先順序 * 的RR進程,其他進程就能夠得到運行了。 */ requeue_task(p, rq->active); } goto out_unlock; }
1.這裡解釋幾個主要的子函數,首先是task_timeslice,重新計算時間片。首先介紹一下基本時間片的概念。
靜態優先順序本質上決定了進程的基本時間片,即進程用完了以前的時間片時,系統分配給進程的時間片長度。靜態優先順序和基本時間片的關係用下列公式確定:
如你所見,靜態優先順序越高(其值越小),基本時間片就越長。其結果是,與優先順序低的進程相比,通常優先順序較高的進程獲得更長的CPU時間片。
#define NICE_TO_PRIO(nice) (MAX_RT_PRIO + (nice) + 20) #define SCALE_PRIO(x, prio) \ max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO/2), MIN_TIMESLICE) static unsigned int task_timeslice(task_t *p) { if (p->static_prio < NICE_TO_PRIO(0)) return SCALE_PRIO(DEF_TIMESLICE*4, p->static_prio); else return SCALE_PRIO(DEF_TIMESLICE, p->static_prio); }
2.requeue_task函數把進程描述符移到與當前進程優先順序相應的運行隊列活動鏈表的尾部。把current指向的進程放到鏈表的尾部,可以保證在每個優先順序與它相同的可運行實時進程獲得CPU時間片以前,它不會再次被選擇來執行。
這是基於時間片輪轉的調度策略。進程描述符的移動通過兩個步驟完成:先調用list_del把進程從運行隊列的活動鏈表中刪除,然後調用list_add_tail把進程重新插入到同一個活動鏈表的尾部。