← 返回 操作系统

操作系统

第五章

第五章的主题是进程管理。前面几章已经让程序能启动、能通过系统调用进入内核、能参与分时调度、也能拥有独立地址空间;ch5 则把“正在运行的程序”进一步封装成可被内核管理的进程对象,让用户程序可以创建子进程、替换自身程序、等待子进程结束、回收资源,并通过优先级参与调度。

这一章最核心的系统调用是 fork、exec、wait、exit。fork 复制当前进程,父子进程从同一位置继续执行但返回值不同;exec 不新建 PID,而是把当前进程的地址空间和用户上下文替换成另一个 ELF 程序;wait 让父进程等待并回收 Zombie 子进程;exit 则把当前进程标记为退出状态,保存退出码,等待父进程回收。

shell 在 ch5 里也被理解成普通用户态进程。它不是内核本身,而是长期运行的用户程序:读取命令,fork 出子进程,让子进程 exec 成目标程序,再由父进程 wait 回收。这样 shell 自己不会被替换掉,命令行可以在每个子程序结束后继续工作。

实验里的 spawn(path, count) 可以看成 fork + exec 的轻量组合:用户态传入目标程序名,内核先翻译 path 这个用户虚拟地址,再从 APPS 表中查找对应 ELF,直接创建一个运行目标程序的新子进程并返回 PID。它训练的重点不是简单新增 syscall,而是把 ch4 的地址翻译、ch5 的父子进程关系和 ELF 加载流程串起来。

ch5 还把 ch4 的 mmap/munmap 迁移到新的进程管理结构里。变化不在于映射算法本身,而在于当前进程的定位方式变了:从简单的 PROCESSES 数组,变成由 PROCESSOR 和 ProcManager 管理当前进程、就绪队列、父子关系与调度状态。

调度部分引入了 stride 算法。每个进程都有 priority 和 stride,每次选择 stride 最小的进程运行;运行后 stride 增加 pass = BIG_STRIDE / priority。priority 越大,pass 越小,stride 增长越慢,因此越容易再次被选中。set_priority 要求优先级至少为 2,初始 priority 为 16,stride 使用大整数避免长期累加和整数除法误差。

代码结构上,ch5 主要由 main.rs、process.rs、processor.rs、graphics.rs、keyboard.rs 和 build.rs 串起来。process.rs 负责进程结构、ELF 加载、fork/exec/sbrk 等逻辑;processor.rs 负责进程管理器、当前进程、就绪队列和 stride 调度;main.rs 则承担内核启动、系统调用实现、内核地址空间和初始进程选择。

这次 ch5 还做了 pingpong 双进程/图形扩展。用户态 ch5_pingpong 维护球、挡板、比分和速度,通过 read(stdin) 读取键盘,通过 write(fd=3) 提交画面帧;内核的 graphics.rs 负责 VirtIO-GPU 输出,keyboard.rs 负责 VirtIO-keyboard 输入。它把进程管理、系统调用、图形设备和输入设备放进了同一个可交互 demo 里。

调试里比较关键的问题包括:build.rs 找不到本地用户程序目录时误走 cargo clone;VirtIO-GPU 因 framebuffer 所需 DMA 内存不足初始化失败;最终通过固定 TG_USER_DIR、降低分辨率并调整 GPU DMA 页数解决。测试上,exercise 和 base 用户测试通过,默认 cargo run 能进入 pingpong 图形链路。

一句话总结 ch5:它把 ch4 中“能运行的独立地址空间”进一步组织成“有 PID、父子关系、生命周期、退出状态和调度属性的进程”,让用户程序能够通过 fork/exec/wait/exit/spawn/set_priority 主动管理其它程序。

GitHub 仓库:flyyansii/Tg-rCore-Tutorial-2026S

ch5 提交:40a9913 add ch5 learning notes

ch5 文档目录:doc/ch5

源码入口:tg-rcore-tutorial-ch5

用户态 pingpong:ch5_pingpong.rs