4. 调度实体与调度类:task_struct中的调度字段、sched_entity结构体、调度类(sched_class)接口与层次结构
Linux内核的进程调度并非直接操作庞大的 task_struct,而是通过抽象层将调度逻辑与进程描述解耦。本章深入剖析调度实体(sched_entity)与调度类(sched_class)的设计,揭示CFS调度器如何通过这两层结构实现高效、可扩展的调度决策。
4.1 task_struct中的调度相关字段
每个进程的 task_struct 中包含一组关键的调度字段,它们是调度器与进程交互的入口。下表列出了核心字段及其作用:
| 字段名 | 类型 | 说明 |
|---|---|---|
prio |
int | 动态优先级,用于实时进程和CFS的nice值映射 |
static_prio |
int | 静态优先级,由nice值计算得出(范围100~139) |
normal_prio |
int | 常规优先级,基于静态优先级和调度策略调整 |
rt_priority |
unsigned int | 实时优先级(0~99),仅用于SCHED_FIFO/SCHED_RR |
sched_class |
const struct sched_class * | 指向该进程所属调度类的指针 |
se |
struct sched_entity | CFS调度实体,嵌入在task_struct中 |
rt |
struct sched_rt_entity | 实时调度实体,用于RT调度类 |
dl |
struct sched_dl_entity | Deadline调度实体,用于SCHED_DEADLINE |
policy |
unsigned int | 调度策略(如SCHED_OTHER、SCHED_FIFO等) |
nr_cpus_allowed |
int | 允许运行的CPU数量 |
cpus_allowed |
struct cpumask | CPU亲和性掩码 |
关键设计点: 每个进程同时包含CFS、RT、DL三种调度实体,但同一时刻只有一个调度类处于活跃状态。调度器通过
sched_class 指针动态切换调度行为。
4.2 sched_entity结构体:CFS的调度单元
sched_entity 是CFS调度器操作的基本单位,它封装了进程在完全公平调度中的全部运行时信息。其核心字段如下:
struct sched_entity {
struct load_weight load; /* 权重,由nice值计算 */
struct rb_node run_node; /* 红黑树节点 */
struct list_head group_node; /* 组调度链表节点 */
unsigned int on_rq; /* 是否在就绪队列上 */
u64 exec_start; /* 当前调度周期开始时间 */
u64 sum_exec_runtime; /* 总执行时间 */
u64 vruntime; /* 虚拟运行时间(核心指标) */
u64 prev_sum_exec_runtime; /* 上次调度时的总执行时间 */
u64 nr_migrations; /* 迁移次数 */
struct sched_statistics statistics; /* 调度统计信息 */
#ifdef CONFIG_FAIR_GROUP_SCHED
struct sched_entity *parent; /* 父调度实体(组调度层级) */
struct cfs_rq *cfs_rq; /* 所属CFS就绪队列 */
struct cfs_rq *my_q; /* 子CFS就绪队列(仅对组有效) */
#endif
};
vruntime 的核心地位: CFS调度器通过维护每个调度实体的
vruntime 值,并选择红黑树中最小的节点作为下一个运行进程,从而实现“完全公平”。vruntime的增长速率受进程权重影响:权重越高,vruntime增长越慢,获得更多CPU时间。
4.3 调度类(sched_class)接口与层次结构
调度类是Linux内核调度子系统实现多态的核心机制。每个调度类实现一组标准接口,内核通过 sched_class 指针统一调用。下图展示了调度类的层次结构与核心接口:
4.4 调度类优先级与选择顺序
调度类按照严格的优先级顺序进行选择。内核在 __pick_next_task 中按以下顺序遍历调度类:
- stop_sched_class — 停止调度类,用于CPU停止操作,优先级最高
- dl_sched_class — Deadline调度类,处理SCHED_DEADLINE策略
- rt_sched_class — 实时调度类,处理SCHED_FIFO和SCHED_RR
- fair_sched_class — CFS调度类,处理SCHED_OTHER、SCHED_BATCH、SCHED_IDLE
- idle_sched_class — 空闲调度类,当没有其他进程可运行时执行
重要约束: 实时进程(rt_sched_class)和Deadline进程(dl_sched_class)会无条件抢占CFS进程。如果系统中存在大量实时进程,CFS进程可能长时间得不到CPU资源。这是设计上的硬实时保证,也是调优时需要关注的风险点。
4.5 调度类接口方法详解
每个调度类必须实现一组标准操作接口,内核通过函数指针表统一调用。下表列出了核心接口方法及其语义:
| 接口方法 | 参数 | 功能描述 |
|---|---|---|
enqueue_task |
rq, p, flags | 将进程p加入就绪队列rq,flags控制唤醒/迁移等行为 |
dequeue_task |
rq, p, flags | 将进程p从就绪队列rq中移除 |
pick_next_task |
rq, p, prev | 选择下一个要运行的进程,返回选中的task_struct指针 |
put_prev_task |
rq, p | 当前进程p被切换出去前的回调,更新统计信息 |
task_tick |
rq, p, queued | 周期性时钟中断触发,检查是否需要抢占或重新调度 |
set_curr_task |
rq, p | 当进程p被选为当前运行进程时调用,初始化调度上下文 |
yield_task |
rq, p | 进程主动让出CPU,调度类决定如何重新排队 |
check_preempt_curr |
rq, p, flags | 检查新唤醒的进程p是否可以抢占当前运行进程 |
switched_from |
rq, p | 进程从当前调度类切换到其他调度类时的清理操作 |
switched_to |
rq, p | 进程切换到当前调度类时的初始化操作 |
4.6 CFS调度类的核心实现路径
以CFS调度类(fair_sched_class)为例,其核心操作路径展示了调度实体与调度类的协作方式:
// 内核源码:kernel/sched/fair.c
// CFS调度类实例定义
const struct sched_class fair_sched_class = {
.next = &idle_sched_class, // 指向下一个优先级更低的调度类
.enqueue_task = enqueue_task_fair,
.dequeue_task = dequeue_task_fair,
.pick_next_task = pick_next_task_fair,
.put_prev_task = put_prev_task_fair,
.task_tick = task_tick_fair,
.set_curr_task = set_curr_task_fair,
.yield_task = yield_task_fair,
.check_preempt_curr = check_preempt_curr_fair,
// ... 其他接口
};
// pick_next_task_fair 核心逻辑(简化)
static struct task_struct *
pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
{
struct cfs_rq *cfs_rq = &rq->cfs;
struct sched_entity *se;
struct task_struct *p;
// 从CFS红黑树中选取vruntime最小的调度实体
se = pick_next_entity(cfs_rq, NULL);
if (!se)
return NULL;
// 将调度实体转换为task_struct
p = task_of(se);
return p;
}
设计模式洞察: 调度类采用“策略模式”(Strategy Pattern),
sched_class 结构体相当于策略接口,每个调度类提供独立实现。核心调度器通过 sched_class 指针调用对应方法,无需关心具体调度算法细节。这种设计使得添加新的调度策略(如曾经的BFS、MuQSS)变得非常容易。
4.7 调度实体与调度类的协作流程
下图展示了从时钟中断触发到进程切换的完整协作流程:
性能关键路径: 从时钟中断到进程切换的整个流程中,
pick_next_task_fair 的红黑树查找操作是CFS调度器的核心性能热点。在拥有数千个进程的系统中,红黑树查找的O(log n)复杂度保证了调度延迟的可预测性。