系列 A · 场景主线:一个程序的一生
这是全系列的主干。9 篇文章沿着 导读 0.1 的状态机总图,一条箭头一条箭头往下走。每篇都只盯 demo 程序生命中的一个时刻,把这个时刻里调度器做的所有事情讲完,包括通用代码、ARM64 代码和 RT 相关的差异。
| 篇目 | demo 此刻在干什么 | 核心问题 | 状态 |
|---|---|---|---|
| A1 fork:一次调用,两次返回 | 父进程在 CPU4 上调 fork() |
子进程的调度实体怎么初始化?放到哪个 CPU?谁来叫醒那个 CPU? | ✅ |
| A2 选核专题:fork / exec / wakeup 三条路 | 子进程 exec、线程被唤醒 | WF_FORK / WF_EXEC / WF_TTWU 选核有什么不同?EAS 何时介入? | |
| A3 第一次上 CPU | CPU2 从 WFI 醒来,第一次运行子进程 | __schedule → cpu_switch_to → ret_from_fork → eret,每一步换了什么? |
✅ |
| A4 运行中:tick、PELT 与时间片 | worker 死循环计算 | vruntime 怎么涨?util 怎么涨?什么时候判定时间片用完? | |
| A5 睡眠:从 set_current_state 到出队 | io 线程 usleep | 为什么先设状态再检查条件?delayed dequeue 是什么? | |
| A6 唤醒:try_to_wake_up 全流程 | 定时器到期唤醒 io | on_cpu 等待、wake list、IPI、唤醒抢占 | |
| A7 抢占:从标记到切换 | ctrl 每 1ms 醒来抢占 worker | 抢占模型对比、两条抢占路径、延迟拆解 | |
| A8 迁移:负载均衡、misfit 与 EAS | worker 从小核被搬到大核 | 谁发起迁移?怎么选目标?迁移时 PELT 怎么带走? | |
| A9 退出:谁来埋葬最后一个栈 | 子进程 return → exit | do_task_dead 之后,栈和 task_struct 由谁释放? |