1 task_struct调度信息
上一节我们说了,task_struct是内核真正的调度对象,代表一个可以被独立执行、阻塞、唤醒和调度的任务。
完整的 task_struct非常庞大,包含一个 task 的各类内核信息。
比如身份信息,内存信息,调度信息等。
调度器拿到一个task后需要根据携带的调度信息进行判断。
其中携带的核心调度信息如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| struct task_struct { unsigned int __state;
unsigned int policy;
int prio; int static_prio; int normal_prio; unsigned int rt_priority;
const struct sched_class *sched_class;
struct sched_entity se; struct sched_rt_entity rt; struct sched_dl_entity dl;
int on_rq;
const cpumask_t *cpus_ptr; cpumask_t cpus_mask; int nr_cpus_allowed;
... };
|
1. policy调度策略
常见的调度策略定义为
1 2 3 4 5 6 7
| #define SCHED_NORMAL 0 #define SCHED_FIFO 1 #define SCHED_RR 2 #define SCHED_BATCH 3
#define SCHED_IDLE 5 #define SCHED_DEADLINE 6
|
其分类如图

2. 优先级
这几个优先级之前我们讲过,在回顾一下
- static_prio:普通任务的静态基础值,主要来自nice
- rt_priority:实时任务的用户可见实时优先级
- normal_prio:根据policy、nice、rt_priority等计算出的正常内部优先级
- prio:调度器当前真正生效的内部优先级
先看prio内部优先级
1 2 3
| #define MAX_RT_PRIO 100 #define MAX_PRIO (MAX_RT_PRIO + 40) #define DEFAULT_PRIO (MAX_RT_PRIO + 20)
|
其分布如图所示

对于用户空间,看见的就是nice值,范围在-20~19,static_prio尤其转换来。
整个优先级的分布和转换如图所示

3. 调度类
核心字段:
1
| const struct sched_class *sched_class;
|
就是调度算法的具体操作,怎么调度。决定task怎样入队和出队,如何判断抢占等操作。

4. 调度实体
被调度的具体对象
1 2 3
| struct sched_entity *parent; struct cfs_rq *cfs_rq; struct cfs_rq *my_q;
|
整体框架

2 runqueue
之前我们说了,per-CPU都有一个管理就绪任务的运行队列。
虽然叫队列,但他的底层并没有队列那么简单。其核心功能主要有以下几点
- 保存可运行任务集合
- 按调度类组织任务
- 保存当前任务
- 保存CPU局部调度状态
- 为选择下一个任务提供选择依据
其简化模型如下

对应核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| struct rq { raw_spinlock_t __lock;
unsigned int nr_running;
struct cfs_rq cfs; struct rt_rq rt; struct dl_rq dl;
struct task_struct *curr; struct task_struct *idle; struct task_struct *stop;
u64 clock; u64 clock_task;
unsigned long nr_uninterruptible; atomic_t nr_iowait;
};
|
3 shed_class
调度的核心,就是为每一种调度算法提供统一的回调函数。
其核心结构如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| struct sched_class { void (*enqueue_task)(struct rq *rq, struct task_struct *p, int flags);
void (*dequeue_task)(struct rq *rq, struct task_struct *p, int flags);
void (*yield_task)(struct rq *rq);
void (*check_preempt_curr)(struct rq *rq, struct task_struct *p, int flags);
struct task_struct *(*pick_next_task)(struct rq *rq);
void (*put_prev_task)(struct rq *rq, struct task_struct *p);
void (*set_next_task)(struct rq *rq, struct task_struct *p, bool first);
void (*task_tick)(struct rq *rq, struct task_struct *p, int queued);
};
|
就是一张调度操作函数指针表。
具体的实现有

以fair_sched_class为例子,其会在以下绑定上面的回调函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| DEFINE_SCHED_CLASS(fair) = {
.enqueue_task = enqueue_task_fair, .dequeue_task = dequeue_task_fair, .yield_task = yield_task_fair, .yield_to_task = yield_to_task_fair,
.wakeup_preempt = check_preempt_wakeup_fair,
.pick_next_task = __pick_next_task_fair, .put_prev_task = put_prev_task_fair, .set_next_task = set_next_task_fair, ... }
|