一文玩轉(zhuǎn)linux內(nèi)核源碼分析之實時調(diào)度!
實時調(diào)度
實時調(diào)度的優(yōu)先級比普通進程高,相應(yīng)的static_prio值總是比普通進程低。
rt_task:宏通過檢測其優(yōu)先級來證實給定進程是否是實時進程 task_has_rt_policy:檢測進程是否是關(guān)聯(lián)到實時調(diào)度策略 SCHED_FIFO:沒有時間片,先進先出,在被調(diào)度器選擇后,可以運行任意長時間。 SCHED_RR:沒有時間片,其值在進程運行時會減少,就像普通進程一樣。在所有的時間段都到期后,則該值重置為初始值,而進程則置于隊列末尾。這確保了在有幾個優(yōu)先級相同的SCHED_RR進程情況下,它們總是依次執(zhí)行
使用場景
SCHED_FIFO應(yīng)用場景,比如時鐘域隔離,不同寬度數(shù)據(jù)接口(如嵌入式單片機8位和16位DSP數(shù)據(jù)傳送,在單片機和DSP連接達到數(shù)據(jù)匹配目的)。
SCHED_RR,需要定時切換場景或輪流實現(xiàn)操作場景
【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。?!前100名進群領(lǐng)取,額外贈送一份價值699的內(nèi)核資料包(含視頻教程、電子書、實戰(zhàn)項目及代碼)??


實時調(diào)度實體 sched_rt_entity
struct sched_rt_entity {
struct list_head run_list;//表頭,維護包含各個進程的一個運行表
unsigned long timeout;//設(shè)置超時時間
unsigned long watchdog_stamp;//記錄jiffies值
unsigned int time_slice;//制定進程可以用CPU的剩余時間段
unsigned short on_rq;
unsigned short on_list;
struct sched_rt_entity *back;//臨時用于從上往下連接RT調(diào)度實體使用
...
} __randomize_layout;
實體調(diào)度類rt_sched_class
const struct sched_class rt_sched_class = {
.next = &fair_sched_class,
.enqueue_task = enqueue_task_rt,//入隊
.dequeue_task = dequeue_task_rt,//出隊
.yield_task = yield_task_rt,//放棄主動權(quán)
.check_preempt_curr = check_preempt_curr_rt,
//調(diào)度器中選擇哪個任務(wù)要被調(diào)度
.pick_next_task = pick_next_task_rt,
.put_prev_task = put_prev_task_rt,//當(dāng)一個任務(wù)將要被調(diào)度出執(zhí)行
.set_next_task ? ? ? ? ?= set_next_task_rt,
}
結(jié)構(gòu)體包含關(guān)系
rt ->rt_rq ->rt_prio_array
struct rq{
struct rt_rq rt;
...
}
struct rt_rq {
struct rt_prio_array active;
unsigned int rt_nr_running;
unsigned int rr_nr_running;
...
}
struct rt_prio_array {
DECLARE_BITMAP(bitmap, MAX_RT_PRIO+1); /* include 1 bit for delimiter */
struct list_head queue[MAX_RT_PRIO];
};
具有相同優(yōu)先級的實時進程都保存在一個鏈表中,表頭為active.queue[prio],而active.bitmap位圖中的每個比特位對應(yīng)一個鏈表,凡是包含進程的鏈表,對應(yīng)的比特位置位。
調(diào)度器操作
以p->prio為所以訪問queue數(shù)組即可得到正確的鏈表,將進程插入/刪除鏈表。新進程排在鏈表的末尾。
pick_next_task_rt

周期調(diào)度實現(xiàn)
static void task_tick_rt(struct rq *rq, struct task_struct *p, int queued)
{
struct sched_rt_entity *rt_se = &p->rt;
update_curr_rt(rq);//更新時間
update_rt_rq_load_avg(rq_clock_pelt(rq), rq, 1);
watchdog(rq, p);
//先進先出的進程沒有時間片,直接退出
if (p->policy != SCHED_RR)
return;
//當(dāng)前是RR進程,則減少時間片
if (--p->rt.time_slice)
return;
//重置時間片100ms
p->rt.time_slice = sched_rr_timeslice;//(100 * HZ / 1000)
//如果該進程不是唯一進程,則排到隊尾
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;
}
}
}
