Sched_ext框架总览

基于 Linux 6.18.26,结合内核源码逐行分析

系列文章:


1. sched_ext 是什么

sched_ext(简称 scx)是 Linux 内核的 eBPF 调度器框架,自 6.12 起合入主线。它允许开发者用 eBPF 程序在用户态编写自定义 CPU 调度策略,而无需修改内核代码或重启系统。

传统上,添加一个新的 Linux 调度器意味着编写一个完整的 sched_class,直接操作内核内部数据结构------这需要内核开发 expertise,修改后必须重新编译、重启才能生效。sched_ext 改变了这个局面:内核提供了一个标准的回调接口(struct sched_ext_ops),开发者只需用 BPF 程序实现这些回调,就能定义一个完整的调度策略。调度器程序可以热加载、热卸载,切换策略时系统中的任务会自动平滑迁移。

可以把 sched_ext 理解为一个"调度器插件系统"------内核在关键调度时机(任务唤醒、入队、出队、开始执行、让出 CPU 等)调用 BPF 回调,BPF 程序在回调中做出调度决策。

1.1 框架总览

#mermaid-svg-twynHwBSqktVInDB{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-twynHwBSqktVInDB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-twynHwBSqktVInDB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-twynHwBSqktVInDB .error-icon{fill:#552222;}#mermaid-svg-twynHwBSqktVInDB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-twynHwBSqktVInDB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-twynHwBSqktVInDB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-twynHwBSqktVInDB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-twynHwBSqktVInDB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-twynHwBSqktVInDB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-twynHwBSqktVInDB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-twynHwBSqktVInDB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-twynHwBSqktVInDB .marker.cross{stroke:#333333;}#mermaid-svg-twynHwBSqktVInDB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-twynHwBSqktVInDB p{margin:0;}#mermaid-svg-twynHwBSqktVInDB .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-twynHwBSqktVInDB .cluster-label text{fill:#333;}#mermaid-svg-twynHwBSqktVInDB .cluster-label span{color:#333;}#mermaid-svg-twynHwBSqktVInDB .cluster-label span p{background-color:transparent;}#mermaid-svg-twynHwBSqktVInDB .label text,#mermaid-svg-twynHwBSqktVInDB span{fill:#333;color:#333;}#mermaid-svg-twynHwBSqktVInDB .node rect,#mermaid-svg-twynHwBSqktVInDB .node circle,#mermaid-svg-twynHwBSqktVInDB .node ellipse,#mermaid-svg-twynHwBSqktVInDB .node polygon,#mermaid-svg-twynHwBSqktVInDB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-twynHwBSqktVInDB .rough-node .label text,#mermaid-svg-twynHwBSqktVInDB .node .label text,#mermaid-svg-twynHwBSqktVInDB .image-shape .label,#mermaid-svg-twynHwBSqktVInDB .icon-shape .label{text-anchor:middle;}#mermaid-svg-twynHwBSqktVInDB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-twynHwBSqktVInDB .rough-node .label,#mermaid-svg-twynHwBSqktVInDB .node .label,#mermaid-svg-twynHwBSqktVInDB .image-shape .label,#mermaid-svg-twynHwBSqktVInDB .icon-shape .label{text-align:center;}#mermaid-svg-twynHwBSqktVInDB .node.clickable{cursor:pointer;}#mermaid-svg-twynHwBSqktVInDB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-twynHwBSqktVInDB .arrowheadPath{fill:#333333;}#mermaid-svg-twynHwBSqktVInDB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-twynHwBSqktVInDB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-twynHwBSqktVInDB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-twynHwBSqktVInDB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-twynHwBSqktVInDB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-twynHwBSqktVInDB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-twynHwBSqktVInDB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-twynHwBSqktVInDB .cluster text{fill:#333;}#mermaid-svg-twynHwBSqktVInDB .cluster span{color:#333;}#mermaid-svg-twynHwBSqktVInDB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-twynHwBSqktVInDB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-twynHwBSqktVInDB rect.text{fill:none;stroke-width:0;}#mermaid-svg-twynHwBSqktVInDB .icon-shape,#mermaid-svg-twynHwBSqktVInDB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-twynHwBSqktVInDB .icon-shape p,#mermaid-svg-twynHwBSqktVInDB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-twynHwBSqktVInDB .icon-shape .label rect,#mermaid-svg-twynHwBSqktVInDB .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-twynHwBSqktVInDB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-twynHwBSqktVInDB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-twynHwBSqktVInDB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 内核空间
用户空间
sched_ext 框架 (kernel/sched/ext.c)
实现 ops 回调
加载/卸载 BPF 程序
读写
查询/更新
调用 sched_class 方法
触发 ops 回调
ext_sched_class
enqueue_task_scx
dequeue_task_scx
balance_scx
pick_task_scx
put_prev_task_scx → stopping
set_next_task_scx → running
BPF 调度器程序

(实现 sched_ext_ops)
用户态工具

(scx CLI / 自定义工具)
struct sched_ext_ops

回调钩子集合
DSQ 调度队列

(Dispatch Queues)
任务状态机

(scx_task_state)
内核核心调度器

(kernel/sched/core.c)

从上图可以看出整个框架的运作方式:

  1. 开发者编写 BPF 调度器程序 ,实现 struct sched_ext_ops 中定义的回调函数。
  2. 用户态工具将 BPF 程序加载到内核,内核注册这些回调。
  3. 内核核心调度器 在调度事件发生时,调用 ext_sched_class 中对应的方法。
  4. ext_sched_class 的方法触发 BPF 回调,BPF 程序在回调中做出调度决策(如选择 CPU、入队到哪个 DSQ、从哪个 DSQ 取出任务等)。
  5. **DSQ(Dispatch Queue)**是 BPF 调度器和内核之间的任务交换枢纽------BPF 程序将任务放入 DSQ,内核从 DSQ 中取出任务送到 CPU。

2. 完整回调总览

2.1 回调一览表

struct sched_ext_ops 代表一个 BPF 调度器,其中定义了多个回调函数。下表列出了所有核心回调:

钩子 触发次数 含义
init_task 每个 task 仅一次 "登记"------task 被 scx 框架认识
enable 每个 task 仅一次 "上岗"------task 被 scx 正式接管
select_cpu 每次唤醒时 "选座"------task 醒来时选择目标 CPU
runnable 每次变为可运行时 "就位"------通知 task 变为 runnable
enqueue 每次入队时 "排队"------task 被放入调度队列
dispatch 每次 CPU 需要任务时 "叫号"------从 DSQ 取出 task 送到 CPU
running 每次调度执行时 "开工"------task 即将占用 CPU
stopping 每次调度结束时 "收工"------task 让出 CPU
quiescent 每次变为不可运行时 "离场"------通知 task 变为 quiescent
set_weight 权重变更时 通知 BPF 调度器 task 的权重
set_cpumask CPU 亲和性变更时 通知允许运行的 CPU 集合

2.2 回调分类

一次性回调(每个 task 仅触发一次):

  • init_task --- 登记,task 被 scx 框架认识
  • enable --- 上岗,task 被 scx 正式接管

状态通知回调(每次状态变化时触发):

  • runnable / quiescent --- 可运行 / 不可运行
  • running / stopping --- 开始执行 / 停止执行
  • set_weight / set_cpumask --- 权重 / 亲和性变更

调度决策回调(核心调度逻辑):

  • select_cpu --- 选核决策,选择目标 CPU
  • enqueue --- 入队决策,放入 DSQ
  • dispatch --- 分发决策,从 DSQ 取出送到 CPU

3. task 生命周期中的回调时序

#mermaid-svg-CFwM216ATxBiiIGM{font-size:30px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CFwM216ATxBiiIGM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CFwM216ATxBiiIGM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CFwM216ATxBiiIGM .error-icon{fill:hsl(220.5882352941, 100%, 98.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .error-text{fill:rgb(8.5000000002, 5.7500000001, 0);stroke:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-CFwM216ATxBiiIGM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CFwM216ATxBiiIGM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CFwM216ATxBiiIGM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CFwM216ATxBiiIGM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CFwM216ATxBiiIGM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CFwM216ATxBiiIGM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CFwM216ATxBiiIGM .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-CFwM216ATxBiiIGM .marker.cross{stroke:#0b0b0b;}#mermaid-svg-CFwM216ATxBiiIGM svg{font-size:30px;}#mermaid-svg-CFwM216ATxBiiIGM p{margin:0;}#mermaid-svg-CFwM216ATxBiiIGM .edge{stroke-width:3;}#mermaid-svg-CFwM216ATxBiiIGM .section--1 rect,#mermaid-svg-CFwM216ATxBiiIGM .section--1 path,#mermaid-svg-CFwM216ATxBiiIGM .section--1 circle,#mermaid-svg-CFwM216ATxBiiIGM .section--1 path{fill:hsl(40.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .section--1 text{fill:#333;}#mermaid-svg-CFwM216ATxBiiIGM .node-icon--1{font-size:40px;color:#333;}#mermaid-svg-CFwM216ATxBiiIGM .section-edge--1{stroke:hsl(40.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .edge-depth--1{stroke-width:17;}#mermaid-svg-CFwM216ATxBiiIGM .section--1 line{stroke:rgb(0, 52.2500000001, 161.5000000002);stroke-width:3;}#mermaid-svg-CFwM216ATxBiiIGM .lineWrapper line{stroke:#333;}#mermaid-svg-CFwM216ATxBiiIGM .disabled,#mermaid-svg-CFwM216ATxBiiIGM .disabled circle,#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:lightgray;}#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:#efefef;}#mermaid-svg-CFwM216ATxBiiIGM .section-0 rect,#mermaid-svg-CFwM216ATxBiiIGM .section-0 path,#mermaid-svg-CFwM216ATxBiiIGM .section-0 circle,#mermaid-svg-CFwM216ATxBiiIGM .section-0 path{fill:hsl(-79.4117647059, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .section-0 text{fill:#333;}#mermaid-svg-CFwM216ATxBiiIGM .node-icon-0{font-size:40px;color:#333;}#mermaid-svg-CFwM216ATxBiiIGM .section-edge-0{stroke:hsl(-79.4117647059, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .edge-depth-0{stroke-width:14;}#mermaid-svg-CFwM216ATxBiiIGM .section-0 line{stroke:rgb(52.2500000001, 161.5000000002, 0);stroke-width:3;}#mermaid-svg-CFwM216ATxBiiIGM .lineWrapper line{stroke:#333;}#mermaid-svg-CFwM216ATxBiiIGM .disabled,#mermaid-svg-CFwM216ATxBiiIGM .disabled circle,#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:lightgray;}#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:#efefef;}#mermaid-svg-CFwM216ATxBiiIGM .section-1 rect,#mermaid-svg-CFwM216ATxBiiIGM .section-1 path,#mermaid-svg-CFwM216ATxBiiIGM .section-1 circle,#mermaid-svg-CFwM216ATxBiiIGM .section-1 path{fill:hsl(220.5882352941, 100%, 73.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .section-1 text{fill:#333;}#mermaid-svg-CFwM216ATxBiiIGM .node-icon-1{font-size:40px;color:#333;}#mermaid-svg-CFwM216ATxBiiIGM .section-edge-1{stroke:hsl(220.5882352941, 100%, 73.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .edge-depth-1{stroke-width:11;}#mermaid-svg-CFwM216ATxBiiIGM .section-1 line{stroke:rgb(136.0000000002, 92.0000000001, 0);stroke-width:3;}#mermaid-svg-CFwM216ATxBiiIGM .lineWrapper line{stroke:#333;}#mermaid-svg-CFwM216ATxBiiIGM .disabled,#mermaid-svg-CFwM216ATxBiiIGM .disabled circle,#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:lightgray;}#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:#efefef;}#mermaid-svg-CFwM216ATxBiiIGM .section-2 rect,#mermaid-svg-CFwM216ATxBiiIGM .section-2 path,#mermaid-svg-CFwM216ATxBiiIGM .section-2 circle,#mermaid-svg-CFwM216ATxBiiIGM .section-2 path{fill:hsl(70.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .section-2 text{fill:#333;}#mermaid-svg-CFwM216ATxBiiIGM .node-icon-2{font-size:40px;color:#333;}#mermaid-svg-CFwM216ATxBiiIGM .section-edge-2{stroke:hsl(70.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .edge-depth-2{stroke-width:8;}#mermaid-svg-CFwM216ATxBiiIGM .section-2 line{stroke:rgb(28.5, 0, 161.5000000002);stroke-width:3;}#mermaid-svg-CFwM216ATxBiiIGM .lineWrapper line{stroke:#333;}#mermaid-svg-CFwM216ATxBiiIGM .disabled,#mermaid-svg-CFwM216ATxBiiIGM .disabled circle,#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:lightgray;}#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:#efefef;}#mermaid-svg-CFwM216ATxBiiIGM .section-3 rect,#mermaid-svg-CFwM216ATxBiiIGM .section-3 path,#mermaid-svg-CFwM216ATxBiiIGM .section-3 circle,#mermaid-svg-CFwM216ATxBiiIGM .section-3 path{fill:hsl(100.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .section-3 text{fill:#333;}#mermaid-svg-CFwM216ATxBiiIGM .node-icon-3{font-size:40px;color:#333;}#mermaid-svg-CFwM216ATxBiiIGM .section-edge-3{stroke:hsl(100.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .edge-depth-3{stroke-width:5;}#mermaid-svg-CFwM216ATxBiiIGM .section-3 line{stroke:rgb(109.2500000001, 0, 161.5000000002);stroke-width:3;}#mermaid-svg-CFwM216ATxBiiIGM .lineWrapper line{stroke:#333;}#mermaid-svg-CFwM216ATxBiiIGM .disabled,#mermaid-svg-CFwM216ATxBiiIGM .disabled circle,#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:lightgray;}#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:#efefef;}#mermaid-svg-CFwM216ATxBiiIGM .section-4 rect,#mermaid-svg-CFwM216ATxBiiIGM .section-4 path,#mermaid-svg-CFwM216ATxBiiIGM .section-4 circle,#mermaid-svg-CFwM216ATxBiiIGM .section-4 path{fill:hsl(130.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .section-4 text{fill:#333;}#mermaid-svg-CFwM216ATxBiiIGM .node-icon-4{font-size:40px;color:#333;}#mermaid-svg-CFwM216ATxBiiIGM .section-edge-4{stroke:hsl(130.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .edge-depth-4{stroke-width:2;}#mermaid-svg-CFwM216ATxBiiIGM .section-4 line{stroke:rgb(161.5000000002, 0, 133.0000000002);stroke-width:3;}#mermaid-svg-CFwM216ATxBiiIGM .lineWrapper line{stroke:#333;}#mermaid-svg-CFwM216ATxBiiIGM .disabled,#mermaid-svg-CFwM216ATxBiiIGM .disabled circle,#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:lightgray;}#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:#efefef;}#mermaid-svg-CFwM216ATxBiiIGM .section-5 rect,#mermaid-svg-CFwM216ATxBiiIGM .section-5 path,#mermaid-svg-CFwM216ATxBiiIGM .section-5 circle,#mermaid-svg-CFwM216ATxBiiIGM .section-5 path{fill:hsl(160.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .section-5 text{fill:#333;}#mermaid-svg-CFwM216ATxBiiIGM .node-icon-5{font-size:40px;color:#333;}#mermaid-svg-CFwM216ATxBiiIGM .section-edge-5{stroke:hsl(160.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .edge-depth-5{stroke-width:-1;}#mermaid-svg-CFwM216ATxBiiIGM .section-5 line{stroke:rgb(161.5000000002, 0, 52.2500000001);stroke-width:3;}#mermaid-svg-CFwM216ATxBiiIGM .lineWrapper line{stroke:#333;}#mermaid-svg-CFwM216ATxBiiIGM .disabled,#mermaid-svg-CFwM216ATxBiiIGM .disabled circle,#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:lightgray;}#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:#efefef;}#mermaid-svg-CFwM216ATxBiiIGM .section-6 rect,#mermaid-svg-CFwM216ATxBiiIGM .section-6 path,#mermaid-svg-CFwM216ATxBiiIGM .section-6 circle,#mermaid-svg-CFwM216ATxBiiIGM .section-6 path{fill:hsl(190.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .section-6 text{fill:#333;}#mermaid-svg-CFwM216ATxBiiIGM .node-icon-6{font-size:40px;color:#333;}#mermaid-svg-CFwM216ATxBiiIGM .section-edge-6{stroke:hsl(190.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .edge-depth-6{stroke-width:-4;}#mermaid-svg-CFwM216ATxBiiIGM .section-6 line{stroke:rgb(161.5000000002, 28.5, 0);stroke-width:3;}#mermaid-svg-CFwM216ATxBiiIGM .lineWrapper line{stroke:#333;}#mermaid-svg-CFwM216ATxBiiIGM .disabled,#mermaid-svg-CFwM216ATxBiiIGM .disabled circle,#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:lightgray;}#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:#efefef;}#mermaid-svg-CFwM216ATxBiiIGM .section-7 rect,#mermaid-svg-CFwM216ATxBiiIGM .section-7 path,#mermaid-svg-CFwM216ATxBiiIGM .section-7 circle,#mermaid-svg-CFwM216ATxBiiIGM .section-7 path{fill:hsl(250.5882352941, 100%, 75%);}#mermaid-svg-CFwM216ATxBiiIGM .section-7 text{fill:#333;}#mermaid-svg-CFwM216ATxBiiIGM .node-icon-7{font-size:40px;color:#333;}#mermaid-svg-CFwM216ATxBiiIGM .section-edge-7{stroke:hsl(250.5882352941, 100%, 75%);}#mermaid-svg-CFwM216ATxBiiIGM .edge-depth-7{stroke-width:-7;}#mermaid-svg-CFwM216ATxBiiIGM .section-7 line{stroke:rgb(105, 127.5, 0);stroke-width:3;}#mermaid-svg-CFwM216ATxBiiIGM .lineWrapper line{stroke:#333;}#mermaid-svg-CFwM216ATxBiiIGM .disabled,#mermaid-svg-CFwM216ATxBiiIGM .disabled circle,#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:lightgray;}#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:#efefef;}#mermaid-svg-CFwM216ATxBiiIGM .section-8 rect,#mermaid-svg-CFwM216ATxBiiIGM .section-8 path,#mermaid-svg-CFwM216ATxBiiIGM .section-8 circle,#mermaid-svg-CFwM216ATxBiiIGM .section-8 path{fill:hsl(310.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .section-8 text{fill:#333;}#mermaid-svg-CFwM216ATxBiiIGM .node-icon-8{font-size:40px;color:#333;}#mermaid-svg-CFwM216ATxBiiIGM .section-edge-8{stroke:hsl(310.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .edge-depth-8{stroke-width:-10;}#mermaid-svg-CFwM216ATxBiiIGM .section-8 line{stroke:rgb(0, 161.5000000002, 28.5);stroke-width:3;}#mermaid-svg-CFwM216ATxBiiIGM .lineWrapper line{stroke:#333;}#mermaid-svg-CFwM216ATxBiiIGM .disabled,#mermaid-svg-CFwM216ATxBiiIGM .disabled circle,#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:lightgray;}#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:#efefef;}#mermaid-svg-CFwM216ATxBiiIGM .section-9 rect,#mermaid-svg-CFwM216ATxBiiIGM .section-9 path,#mermaid-svg-CFwM216ATxBiiIGM .section-9 circle,#mermaid-svg-CFwM216ATxBiiIGM .section-9 path{fill:hsl(340.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .section-9 text{fill:#333;}#mermaid-svg-CFwM216ATxBiiIGM .node-icon-9{font-size:40px;color:#333;}#mermaid-svg-CFwM216ATxBiiIGM .section-edge-9{stroke:hsl(340.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .edge-depth-9{stroke-width:-13;}#mermaid-svg-CFwM216ATxBiiIGM .section-9 line{stroke:rgb(0, 161.5000000002, 109.2500000001);stroke-width:3;}#mermaid-svg-CFwM216ATxBiiIGM .lineWrapper line{stroke:#333;}#mermaid-svg-CFwM216ATxBiiIGM .disabled,#mermaid-svg-CFwM216ATxBiiIGM .disabled circle,#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:lightgray;}#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:#efefef;}#mermaid-svg-CFwM216ATxBiiIGM .section-10 rect,#mermaid-svg-CFwM216ATxBiiIGM .section-10 path,#mermaid-svg-CFwM216ATxBiiIGM .section-10 circle,#mermaid-svg-CFwM216ATxBiiIGM .section-10 path{fill:hsl(10.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .section-10 text{fill:#333;}#mermaid-svg-CFwM216ATxBiiIGM .node-icon-10{font-size:40px;color:#333;}#mermaid-svg-CFwM216ATxBiiIGM .section-edge-10{stroke:hsl(10.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .edge-depth-10{stroke-width:-16;}#mermaid-svg-CFwM216ATxBiiIGM .section-10 line{stroke:rgb(0, 133.0000000002, 161.5000000002);stroke-width:3;}#mermaid-svg-CFwM216ATxBiiIGM .lineWrapper line{stroke:#333;}#mermaid-svg-CFwM216ATxBiiIGM .disabled,#mermaid-svg-CFwM216ATxBiiIGM .disabled circle,#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:lightgray;}#mermaid-svg-CFwM216ATxBiiIGM .disabled text{fill:#efefef;}#mermaid-svg-CFwM216ATxBiiIGM .section-root rect,#mermaid-svg-CFwM216ATxBiiIGM .section-root path,#mermaid-svg-CFwM216ATxBiiIGM .section-root circle{fill:hsl(40.5882352941, 100%, 68.3333333333%);}#mermaid-svg-CFwM216ATxBiiIGM .section-root text{fill:#333;}#mermaid-svg-CFwM216ATxBiiIGM .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-CFwM216ATxBiiIGM .edge{fill:none;}#mermaid-svg-CFwM216ATxBiiIGM .eventWrapper{filter:brightness(120%);}#mermaid-svg-CFwM216ATxBiiIGM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 创建阶段 init_task 登记进入 scx 框架 enable 被 scx 正式接管 每次唤醒 select_cpu 选择目标 CPU runnable 通知 task 可运行 enqueue 放入调度队列 每次调度 dispatch 从 DSQ 取出 task 送到 CPU running 开始占用 CPU ... 执行任务 ... stopping 让出 CPU 销毁 disable 脱离 scx 管理 task 生命周期中的 scx 回调时序

3.1 一次性回调 vs 重复回调

#mermaid-svg-xJVdp9a6dcbGnv7D{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-xJVdp9a6dcbGnv7D .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xJVdp9a6dcbGnv7D .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xJVdp9a6dcbGnv7D .error-icon{fill:#552222;}#mermaid-svg-xJVdp9a6dcbGnv7D .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xJVdp9a6dcbGnv7D .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xJVdp9a6dcbGnv7D .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xJVdp9a6dcbGnv7D .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xJVdp9a6dcbGnv7D .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xJVdp9a6dcbGnv7D .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xJVdp9a6dcbGnv7D .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xJVdp9a6dcbGnv7D .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xJVdp9a6dcbGnv7D .marker.cross{stroke:#333333;}#mermaid-svg-xJVdp9a6dcbGnv7D svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xJVdp9a6dcbGnv7D p{margin:0;}#mermaid-svg-xJVdp9a6dcbGnv7D .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-xJVdp9a6dcbGnv7D .cluster-label text{fill:#333;}#mermaid-svg-xJVdp9a6dcbGnv7D .cluster-label span{color:#333;}#mermaid-svg-xJVdp9a6dcbGnv7D .cluster-label span p{background-color:transparent;}#mermaid-svg-xJVdp9a6dcbGnv7D .label text,#mermaid-svg-xJVdp9a6dcbGnv7D span{fill:#333;color:#333;}#mermaid-svg-xJVdp9a6dcbGnv7D .node rect,#mermaid-svg-xJVdp9a6dcbGnv7D .node circle,#mermaid-svg-xJVdp9a6dcbGnv7D .node ellipse,#mermaid-svg-xJVdp9a6dcbGnv7D .node polygon,#mermaid-svg-xJVdp9a6dcbGnv7D .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-xJVdp9a6dcbGnv7D .rough-node .label text,#mermaid-svg-xJVdp9a6dcbGnv7D .node .label text,#mermaid-svg-xJVdp9a6dcbGnv7D .image-shape .label,#mermaid-svg-xJVdp9a6dcbGnv7D .icon-shape .label{text-anchor:middle;}#mermaid-svg-xJVdp9a6dcbGnv7D .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-xJVdp9a6dcbGnv7D .rough-node .label,#mermaid-svg-xJVdp9a6dcbGnv7D .node .label,#mermaid-svg-xJVdp9a6dcbGnv7D .image-shape .label,#mermaid-svg-xJVdp9a6dcbGnv7D .icon-shape .label{text-align:center;}#mermaid-svg-xJVdp9a6dcbGnv7D .node.clickable{cursor:pointer;}#mermaid-svg-xJVdp9a6dcbGnv7D .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-xJVdp9a6dcbGnv7D .arrowheadPath{fill:#333333;}#mermaid-svg-xJVdp9a6dcbGnv7D .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-xJVdp9a6dcbGnv7D .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-xJVdp9a6dcbGnv7D .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xJVdp9a6dcbGnv7D .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-xJVdp9a6dcbGnv7D .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xJVdp9a6dcbGnv7D .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-xJVdp9a6dcbGnv7D .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-xJVdp9a6dcbGnv7D .cluster text{fill:#333;}#mermaid-svg-xJVdp9a6dcbGnv7D .cluster span{color:#333;}#mermaid-svg-xJVdp9a6dcbGnv7D div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xJVdp9a6dcbGnv7D .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-xJVdp9a6dcbGnv7D rect.text{fill:none;stroke-width:0;}#mermaid-svg-xJVdp9a6dcbGnv7D .icon-shape,#mermaid-svg-xJVdp9a6dcbGnv7D .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xJVdp9a6dcbGnv7D .icon-shape p,#mermaid-svg-xJVdp9a6dcbGnv7D .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-xJVdp9a6dcbGnv7D .icon-shape .label rect,#mermaid-svg-xJVdp9a6dcbGnv7D .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xJVdp9a6dcbGnv7D .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-xJVdp9a6dcbGnv7D .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-xJVdp9a6dcbGnv7D :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 仅一次
仅一次
循环
ops.init_task()
ops.enable()
enqueue / dequeue
ops.dispatch()
ops.running()
task 在 CPU 上执行
ops.stopping()

init_taskenable 是"一次性门禁",只在 task 进入 scx 管理时各触发一次;而 runningstopping 是"旋转门",每次 task 被调度到 CPU 或让出 CPU 时都会触发,构成调度循环。


4. task 的四种状态

每个 task 在 scx 框架中都有一个状态,记录在 task->scx.state 中:

c 复制代码
// include/linux/sched/ext.h
enum scx_task_state {
    SCX_TASK_NONE,       // ops.init_task() 还没被调用
    SCX_TASK_INIT,       // init_task 执行成功,但任务还没就绪
    SCX_TASK_READY,      // 完全初始化,可以被 scx 调度
    SCX_TASK_ENABLED,    // 已激活,正在被 scx 调度

    SCX_TASK_NR_STATES,
};

状态流转图:
#mermaid-svg-wqfMPiDe99byKUjf{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-wqfMPiDe99byKUjf .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-wqfMPiDe99byKUjf .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-wqfMPiDe99byKUjf .error-icon{fill:#552222;}#mermaid-svg-wqfMPiDe99byKUjf .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-wqfMPiDe99byKUjf .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-wqfMPiDe99byKUjf .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-wqfMPiDe99byKUjf .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-wqfMPiDe99byKUjf .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-wqfMPiDe99byKUjf .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-wqfMPiDe99byKUjf .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-wqfMPiDe99byKUjf .marker{fill:#333333;stroke:#333333;}#mermaid-svg-wqfMPiDe99byKUjf .marker.cross{stroke:#333333;}#mermaid-svg-wqfMPiDe99byKUjf svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-wqfMPiDe99byKUjf p{margin:0;}#mermaid-svg-wqfMPiDe99byKUjf defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-wqfMPiDe99byKUjf g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-wqfMPiDe99byKUjf g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-wqfMPiDe99byKUjf g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-wqfMPiDe99byKUjf g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-wqfMPiDe99byKUjf g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-wqfMPiDe99byKUjf .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-wqfMPiDe99byKUjf .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-wqfMPiDe99byKUjf .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-wqfMPiDe99byKUjf .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-wqfMPiDe99byKUjf .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-wqfMPiDe99byKUjf .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-wqfMPiDe99byKUjf .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-wqfMPiDe99byKUjf .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wqfMPiDe99byKUjf .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-wqfMPiDe99byKUjf .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wqfMPiDe99byKUjf .edgeLabel .label text{fill:#333;}#mermaid-svg-wqfMPiDe99byKUjf .label div .edgeLabel{color:#333;}#mermaid-svg-wqfMPiDe99byKUjf .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-wqfMPiDe99byKUjf .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-wqfMPiDe99byKUjf .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-wqfMPiDe99byKUjf .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-wqfMPiDe99byKUjf .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-wqfMPiDe99byKUjf .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-wqfMPiDe99byKUjf .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-wqfMPiDe99byKUjf #statediagram-barbEnd{fill:#333333;}#mermaid-svg-wqfMPiDe99byKUjf .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-wqfMPiDe99byKUjf .cluster-label,#mermaid-svg-wqfMPiDe99byKUjf .nodeLabel{color:#131300;}#mermaid-svg-wqfMPiDe99byKUjf .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-wqfMPiDe99byKUjf .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-wqfMPiDe99byKUjf .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-wqfMPiDe99byKUjf .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-wqfMPiDe99byKUjf .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-wqfMPiDe99byKUjf .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-wqfMPiDe99byKUjf .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-wqfMPiDe99byKUjf .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-wqfMPiDe99byKUjf .note-edge{stroke-dasharray:5;}#mermaid-svg-wqfMPiDe99byKUjf .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-wqfMPiDe99byKUjf .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-wqfMPiDe99byKUjf .statediagram-note text{fill:black;}#mermaid-svg-wqfMPiDe99byKUjf .statediagram-note .nodeLabel{color:black;}#mermaid-svg-wqfMPiDe99byKUjf .statediagram .edgeLabel{color:red;}#mermaid-svg-wqfMPiDe99byKUjf #dependencyStart,#mermaid-svg-wqfMPiDe99byKUjf #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-wqfMPiDe99byKUjf .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-wqfMPiDe99byKUjf :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 任务创建
init_task 成功返回
注册时 第一轮遍历

fork时 scx_post_fork
sched_class == ext

switching_to_scx 或 scx_post_fork 中 enable
sched_class != ext,保持 READY
调度器卸载或策略切换
SCX_TASK_NONE
SCX_TASK_INIT
SCX_TASK_READY
SCX_TASK_ENABLED

状态 含义
SCX_TASK_NONE 初始状态,还未被 scx 认识
SCX_TASK_INIT 短暂中间态,init_task 返回 0 后立即进入
SCX_TASK_READY 完全初始化,可以被 scx 调度
SCX_TASK_ENABLED 激活态,正在被 scx 调度,ops.enable() 已调用

SCX_TASK_INIT 是一个中间态,只在 scx_init_task() 执行成功后短暂存在,紧接着就会被推进到 READY。


5. ext_sched_class 全貌

sched_ext 在内核中注册为 ext_sched_class,它是完整的 Linux 调度类(sched_class)。内核核心调度器在调度事件发生时,统一通过 sched_class 的方法指针来调用 scx 的实现。为方便后续各篇分析时对照,这里给出 ext_sched_class 的完整定义(kernel/sched/ext.c:3324):

c 复制代码
DEFINE_SCHED_CLASS(ext) = {
    .enqueue_task       = enqueue_task_scx,
    .dequeue_task       = dequeue_task_scx,
    .yield_task         = yield_task_scx,
    .yield_to_task      = yield_to_scx,

    .wakeup_preempt     = wakeup_preempt_scx,

    .balance            = balance_scx,
    .pick_task          = pick_task_scx,

    .put_prev_task      = put_prev_task_scx,     // ← stopping 在这里触发
    .set_next_task      = set_next_task_scx,     // ← running 在这里触发

    .select_task_rq     = select_task_rq_scx,
    .task_woken         = task_woken_scx,
    .set_cpus_allowed   = set_cpus_allowed_scx,

    .rq_online          = rq_online_scx,
    .rq_offline         = rq_offline_scx,

    .task_tick          = task_tick_scx,

    .switching_to       = switching_to_scx,
    .switched_from      = switched_from_scx,
    .switched_to        = switched_to_scx,
    .reweight_task      = reweight_task_scx,
    .prio_changed       = prio_changed_scx,

    .update_curr        = update_curr_scx,

#ifdef CONFIG_UCLAMP_TASK
    .uclamp_enabled    = 1,
#endif
};

注意两个关键点:

  1. ext_sched_class 没有 pick_next_task 方法 ,只有 pick_task。这意味着在 __pick_next_task 中,scx 走的是 class->pick_task(rq) + put_prev_set_next_task() 分支,而不是 class->pick_next_task(rq, prev) 分支。
  2. running 和 stopping 分别挂接在 set_next_taskput_prev_task 。这两个方法在每次调度切换时成对调用:先 put_prev_task(旧任务 stopping),再 set_next_task(新任务 running)。

6. 小结与系列导航

本文从宏观角度描绘了 sched_ext 框架的全貌:

  • 架构层面 :sched_ext 是一个 eBPF 驱动的调度器插件系统,用户态 BPF 程序通过实现 struct sched_ext_ops 中的回调来定义调度策略,内核在关键调度时机调用这些回调。
  • 回调体系 :11 个核心回调分为三类------一次性回调(init_taskenable)、状态通知回调(runnable/quiescentrunning/stopping 等)和调度决策回调(select_cpuenqueuedispatch)。
  • 状态机 :task 在 scx 框架中经历 NONE → INIT → READY → ENABLED 四个状态,其中 INIT 是短暂中间态,ENABLED 是正常运行态。
  • 调度类集成ext_sched_class 作为标准的 Linux sched_class 注册到内核,核心调度器通过统一接口调用 scx 的实现。

理解了框架全貌之后,后续文章将逐一深入每个回调的内核实现细节。建议按以下顺序阅读:

  1. init_task ------ 每个 task 走进调度器的第一道门,理解 task 如何被 scx 框架"登记"
  2. enable ------ task 被 scx 正式接管的关键时刻,理解状态从 READY 到 ENABLED 的跃迁
  3. select_cpu ------ 任务唤醒时的选核决策,理解 BPF 调度器如何影响 CPU 选择
  4. runnable ------ 任务状态转换的哨兵,理解 runnable/quiescent 的对称设计
  5. enqueue ------ 任务入队,理解 DSQ 机制和调度决策的核心逻辑
  6. dispatch ------ 从 DSQ 取出任务送到 CPU,理解分发机制的完整流程
  7. running ------ 任务开始执行,理解 running/stopping 的成对设计
相关推荐
Dlrb12111 小时前
Linux系统编程-进程及相关指令与函数
linux·进程·并发·进程状态·调度·进程控制指令·进程函数
奋斗的好青年2 小时前
Ubuntu 修复 GRUB 引导并找回 Windows 双系统启动项(NVMe + MBR 环境)
linux·windows·ubuntu
开发者联盟league2 小时前
在ubuntu上安装harbor
linux·运维·ubuntu
ulias2124 小时前
深挖进程间通信的奥秘
java·linux·服务器·开发语言·c++·算法
AOwhisky4 小时前
MySQL 学习笔记(第三期):SQL 语言之数据操作与单表查询
linux·运维·笔记·sql·学习·mysql·云计算
键盘上的猫头鹰4 小时前
【Linux 基础教程(四)】文件内容查看、打包压缩与搜索、重定向管道及环境变量
linux·服务器·python
tellmewhoisi4 小时前
linux 基础知识(文件权限相关)
linux·运维·服务器
jiayong235 小时前
Claude Code 常见操作实战指南
linux·服务器·网络·ai·claude·claude code
醇氧5 小时前
【Linux 】sudo、sudo -i、su、su - 完整区别总结
linux·运维·服务器