日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux 进程调度源码分析,Linux调度器源码分析

發布時間:2024/9/27 linux 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 进程调度源码分析,Linux调度器源码分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

代碼分析根據3.10版本

通過對前面的學習我們知道Linux的調度分為兩種

周期調度 完成周期性算法參數的更新和系統其它實際的檢查

主調的 真正的調度過程

我們現在來看下主調的的代碼框架。

入口

根《調度發生的情況》的學習,我們知道所有的調度最后都會到 schedule 函數中。因此我們就先從schedule函數入手。

asmlinkage void __sched schedule(void)

{

struct task_struct *tsk = current;

sched_submit_work(tsk);//獲取當前current 并且加鎖。

__schedule();

}

schedule 函數并沒有太多的操作,只是獲取當前task,然后加鎖,最后都交給了**__schedule()**函數。

主要框架

主要函數__schedule分析

static 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();

rq = cpu_rq(cpu);//找到當前cpu拿取隊列

prev = rq->curr;//保持此時此刻的任務

.....

pre_schedule(rq, prev);//做一些預處理

....

put_prev_task(rq, prev);

next = pick_next_task(rq);//選取下一個進程

clear_tsk_need_resched(prev);

rq->skip_clock_update = 0;

if (likely(prev != next)) {//選好了,

rq->nr_switches++;

rq->curr = next;

++*switch_count;//計數加一

...

context_switch(rq, prev, next); /* unlocks the rq */真正的切換堆棧幀

...

cpu = smp_processor_id();

rq = cpu_rq(cpu);

} else

raw_spin_unlock_irq(&rq->lock);

....

if (need_resched())//是否需要重新調度

goto need_resched;

}

其實**__schedule**還是比較長的,但是我們這里選擇了一些主要的流程分析,流程如下:

1、拿到當前cpu的隊列rq

2、進行一些與操作處理

3、選取下一個進程

4、堆棧幀context_switch 切換

5、是否需要重新調度

關于重新調度,設計到一些內核搶占的知識,我們暫時不分析。而context_switch,是硬件堆棧的切換,我們后文會認真分析這個函數,在這個過程中我們主要關注如何選取下一個進程。

如何選取下一個任務 pick_next_task 函數分析

static inline struct task_struct * pick_next_task(struct rq *rq)

{

const struct sched_class *class;

struct task_struct *p;

/*

* Optimization: we know that if all tasks are in

* the fair class we can call that function directly:

*/

if (likely(rq->nr_running == rq->cfs.h_nr_running)) {檢查當前cpu隊列中是否所有的都是cfs,如果是就直接掉用cfs的調度類

p = fair_sched_class.pick_next_task(rq);

if (likely(p))

return p;

}

for_each_class(class) {循環遍歷每一個調度類

p = class->pick_next_task(rq);

if (p)

return p;

}

}

pick_next_task 還是比較簡單的只是有兩部, 1、查看當前cpu隊列是否所有的都是cfs 2、遍歷所有調度類。 對于是不是全部cfs的檢查是有必要的,會減少開銷。我們再來看下遍歷

#define sched_class_highest (&stop_sched_class)

#define for_each_class(class) \

for (class = sched_class_highest; class; class = class->next)

extern const struct sched_class stop_sched_class;

extern const struct sched_class rt_sched_class;

extern const struct sched_class fair_sched_class;

extern const struct sched_class idle_sched_class;

我們看到是從stop_sched_class開始,

const struct sched_class stop_sched_class = {

.next= &rt_sched_class,

....

}

const struct sched_class rt_sched_class = {

.next= &fair_sched_class,

....

}

const struct sched_class fair_sched_class = {

.next= &idle_sched_class,

....

}

const struct sched_class idle_sched_class = {

/* .next is NULL */

....

}

可以看到是這么個列表。

stop_sched_class --》rt_sched_class--》fair_sched_class--》idle_sched_class--》NULL

以cfs為例看看如何選取task

static struct task_struct *pick_next_task_fair(struct rq *rq)

{

struct task_struct *p;

struct cfs_rq *cfs_rq = &rq->cfs;

struct sched_entity *se;

if (!cfs_rq->nr_running)

return NULL;

do {

se = pick_next_entity(cfs_rq);

set_next_entity(cfs_rq, se);

cfs_rq = group_cfs_rq(se);

} while (cfs_rq);

p = task_of(se);

if (hrtick_enabled(rq))

hrtick_start_fair(rq, p);

return p;

}

這部分代碼也是組調度流程的基礎,現在看起來是比較簡單的,但是接下來分析組調度的時候就會詳細的展開分析。 我們看這個簡單的過程:

全局的rq 拿到cfs_rq

cfs_rq 通過pick_next_entity 拿到算法算好的調度類entity----se。

進行組調度----目前先忽略

將se 轉換成task 這樣就結束了主調的的所有過程。

總結

以上是生活随笔為你收集整理的linux 进程调度源码分析,Linux调度器源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。