- 论坛徽章:
- 0
|
linux内核分析之调度算法(三) - struct sched_class {
- /*會指向下一個Scheduling Class,以筆者所採用
- 的Linux Kernel 2.6.38.6而言,Scheduling Class的順序為
- stop_sched_class->rt_sched_class->fair_sched_class->idle_sched_class*/
- const struct sched_class *next;
- /*當Task屬於Runnable狀態時,就會呼叫這個函式
- 把Task配置到RunQueue RBTree中,進行排程動作,
- 並呼叫inc_nr_running將RunQueue中nr_running的值
- 加一.(nr_running用以代表目前RunQueue有多少
- Runnable Task進行排程)*/
- void (*enqueue_task) (struct rq *rq, struct task_struct *p, int wakeup);
- /*當Task不需要執行時,就會呼叫這個函式
- 把Task從RunQueue RBTree中移除,並呼叫
- dec_nr_running將RunQueue中nr_running的值減一.*/
- void (*dequeue_task) (struct rq *rq, struct task_struct *p, int sleep);
- /*用以暫停目前正在執行中的Task,如果
- sysctl_sched_compat_yield有設定,就會找出目前
- RBTree中最右邊的Task(也就是vrruntime最多
- 的Task),讓目前Task的vrruntime值等於最右邊
- Task值的vrruntime加一(可參考:
- se->vruntime = rightmost->vruntime + 1),如此在下次
- 排程觸發時就會透過函式put_prev_task把目前
- 的Task放到RBTree的最右邊,也就等同於暫停
- Task,讓該Task下次被執行到的機會最低.*/
- void (*yield_task) (struct rq *rq);
- /*用以決定一個Task是否可以中斷目前正在
- 運作的Task,取得執行權.以CFS本身的實作來說
- (in sched_fair.c).如果想要取代目前Task的Task本身
- 的Scheduling Policy為 Batch或是Idle時,會直接返回,
- 不會用來取代目前正在執行中的Task.反之,
- 如果目前正在執行中的Task的Scheduling Policy
- 為Idle,就會直接由所傳入的Task取代目前正
- 在執行的Task.*/
- void (*check_preempt_curr) (struct rq *rq, struct task_struct *p, int flags);
- /*用以在排程觸發時,從RunQueue RBTree中,
- 取出符合目前Scheduling邏輯的下一個要
- 被執行的Task.*/
- struct task_struct * (*pick_next_task) (struct rq *rq);
- /*用以在排程觸發時,把上一個執行完畢的
- Task放到目前RunQueue RBTree中對應的位置.*/
- void (*put_prev_task) (struct rq *rq, struct task_struct *p);
-
- #ifdef CONFIG_SMP
- /*通常用在執行一個新的程序,或是WakeUp
- 一個Task時,會根據目前SMP下每個處理器的
- 負荷,決定Task是否要切換到另一個處理器
- 的RunQueue去執行,執行時會返回最後目標
- 處理器的值.*/
- int (*select_task_rq)(struct task_struct *p, int sd_flag, int flags);
-
- unsigned long (*load_balance) (struct rq *this_rq, int this_cpu,
- struct rq *busiest, unsigned long max_load_move,
- struct sched_domain *sd, enum cpu_idle_type idle,
- int *all_pinned, int *this_best_prio);
-
- int (*move_one_task) (struct rq *this_rq, int this_cpu,
- struct rq *busiest, struct sched_domain *sd,
- enum cpu_idle_type idle);
- void (*pre_schedule) (struct rq *this_rq, struct task_struct *task);
- void (*post_schedule) (struct rq *this_rq);
- void (*task_wake_up) (struct rq *this_rq, struct task_struct *task);
-
- void (*set_cpus_allowed)(struct task_struct *p,
- const struct cpumask *newmask);
-
- void (*rq_online)(struct rq *rq);
- void (*rq_offline)(struct rq *rq);
- #endif
- /*這個函式用以改變Task目前所屬的Scheduling
- Class與改變Task Group.*/
- void (*set_curr_task) (struct rq *rq);
- /*這是Scheduler的 Timer Tick來源,系統中觸發的
- Scheduling Tick會呼叫這個函式 (看HZ設定多少,
- 100就是每秒呼叫這函式100次,1000就是每秒
- 呼叫這函式1000次),
- 用以讓排程機制可以決定哪些Task應該要配
- 執行與哪些Task應該要被移出RunQueue.*/
- void (*task_tick) (struct rq *rq, struct task_struct *p, int queued);
- void (*task_new) (struct rq *rq, struct task_struct *p);
-
- void (*switched_from) (struct rq *this_rq, struct task_struct *task,
- int running);
- void (*switched_to) (struct rq *this_rq, struct task_struct *task,
- int running);
- void (*prio_changed) (struct rq *this_rq, struct task_struct *task,
- int oldprio, int running);
-
- unsigned int (*get_rr_interval) (struct task_struct *task);
-
- #ifdef CONFIG_FAIR_GROUP_SCHED
- void (*moved_group) (struct task_struct *p);
- #endif
- };
- /*CFS排程機制在設計時,考慮到排程機制的
- 彈性,定義了Scheduler Class的機制,讓排程機制
- 可以根據設計的需求,延伸不同的排程模
- 組進來,每個新加入的排程機制都必須要
- 提供Scheduler Class的實作,結構為 struct sched_class*/
- struct sched_class {
- /*會指向下一個Scheduling Class,以筆者所採用
- 的Linux Kernel 2.6.38.6而言,Scheduling Class的順序為
- stop_sched_class->rt_sched_class->fair_sched_class->idle_sched_class*/
- const struct sched_class *next;
- /*當Task屬於Runnable狀態時,就會呼叫這個函式
- 把Task配置到RunQueue RBTree中,進行排程動作,
- 並呼叫inc_nr_running將RunQueue中nr_running的值
- 加一.(nr_running用以代表目前RunQueue有多少
- Runnable Task進行排程)*/
- void (*enqueue_task) (struct rq *rq, struct task_struct *p, int wakeup);
- /*當Task不需要執行時,就會呼叫這個函式
- 把Task從RunQueue RBTree中移除,並呼叫
- dec_nr_running將RunQueue中nr_running的值減一.*/
- void (*dequeue_task) (struct rq *rq, struct task_struct *p, int sleep);
- /*用以暫停目前正在執行中的Task,如果
- sysctl_sched_compat_yield有設定,就會找出目前
- RBTree中最右邊的Task(也就是vrruntime最多
- 的Task),讓目前Task的vrruntime值等於最右邊
- Task值的vrruntime加一(可參考:
- se->vruntime = rightmost->vruntime + 1),如此在下次
- 排程觸發時就會透過函式put_prev_task把目前
- 的Task放到RBTree的最右邊,也就等同於暫停
- Task,讓該Task下次被執行到的機會最低.*/
- void (*yield_task) (struct rq *rq);
- /*用以決定一個Task是否可以中斷目前正在
- 運作的Task,取得執行權.以CFS本身的實作來說
- (in sched_fair.c).如果想要取代目前Task的Task本身
- 的Scheduling Policy為 Batch或是Idle時,會直接返回,
- 不會用來取代目前正在執行中的Task.反之,
- 如果目前正在執行中的Task的Scheduling Policy
- 為Idle,就會直接由所傳入的Task取代目前正
- 在執行的Task.*/
- void (*check_preempt_curr) (struct rq *rq, struct task_struct *p, int flags);
- /*用以在排程觸發時,從RunQueue RBTree中,
- 取出符合目前Scheduling邏輯的下一個要
- 被執行的Task.*/
- struct task_struct * (*pick_next_task) (struct rq *rq);
- /*用以在排程觸發時,把上一個執行完畢的
- Task放到目前RunQueue RBTree中對應的位置.*/
- void (*put_prev_task) (struct rq *rq, struct task_struct *p);
- #ifdef CONFIG_SMP
- /*通常用在執行一個新的程序,或是WakeUp
- 一個Task時,會根據目前SMP下每個處理器的
- 負荷,決定Task是否要切換到另一個處理器
- 的RunQueue去執行,執行時會返回最後目標
- 處理器的值.*/
- int (*select_task_rq)(struct task_struct *p, int sd_flag, int flags);
- unsigned long (*load_balance) (struct rq *this_rq, int this_cpu,
- struct rq *busiest, unsigned long max_load_move,
- struct sched_domain *sd, enum cpu_idle_type idle,
- int *all_pinned, int *this_best_prio);
- int (*move_one_task) (struct rq *this_rq, int this_cpu,
- struct rq *busiest, struct sched_domain *sd,
- enum cpu_idle_type idle);
- void (*pre_schedule) (struct rq *this_rq, struct task_struct *task);
- void (*post_schedule) (struct rq *this_rq);
- void (*task_wake_up) (struct rq *this_rq, struct task_struct *task);
- void (*set_cpus_allowed)(struct task_struct *p,
- const struct cpumask *newmask);
- void (*rq_online)(struct rq *rq);
- void (*rq_offline)(struct rq *rq);
- #endif
- /*這個函式用以改變Task目前所屬的Scheduling
- Class與改變Task Group.*/
- void (*set_curr_task) (struct rq *rq);
- /*這是Scheduler的 Timer Tick來源,系統中觸發的
- Scheduling Tick會呼叫這個函式 (看HZ設定多少,
- 100就是每秒呼叫這函式100次,1000就是每秒
- 呼叫這函式1000次),
- 用以讓排程機制可以決定哪些Task應該要配
- 執行與哪些Task應該要被移出RunQueue.*/
- void (*task_tick) (struct rq *rq, struct task_struct *p, int queued);
- void (*task_new) (struct rq *rq, struct task_struct *p);
- void (*switched_from) (struct rq *this_rq, struct task_struct *task,
- int running);
- void (*switched_to) (struct rq *this_rq, struct task_struct *task,
- int running);
- void (*prio_changed) (struct rq *this_rq, struct task_struct *task,
- int oldprio, int running);
- unsigned int (*get_rr_interval) (struct task_struct *task);
- #ifdef CONFIG_FAIR_GROUP_SCHED
- void (*moved_group) (struct task_struct *p);
- #endif
- };
-
复制代码 调度实体,调度实体用于调度时间记账,linux中CFS和实时调度使用不同的调度实体。调度运行队列,对于不用的调度算法同样运用不用的运行队列,对于CFS调度,运用的是红黑树,而对于实时调度为组链表。在后面具体的调度算法介绍中我们会看到他们的运用。
|
|