从零写OS(二十):wait / exit 完整语义

上一章实现了 exec(),用户程序能跑起来了。但进程退出时只是把进程表项清掉,父进程拿不到退出码,也没有办法等待。这一章实现完整的 exit / wait 语义。 为什么进程退出后不能直接消失 直觉上,进程退出就应该立刻清掉进程表项。但这里有个问题:父进程怎么拿到子进程的退出码? 如果进程表项直接清掉,退出码就丢了。父进程调用 wait() 的时机可能比子进程 exit() 晚,也可能早——无论哪种情况,父进程都需要能读到那个退出码。 Linux 的解法是引入**僵尸(zombie)**状态:进程 exit() 后不立即消失,保留退出码,等父进程 wait() 读取后才彻底释放。 这就是为什么 ps 输出里偶尔会出现状态为 Z 的进程——它已经退出了,只是在等父进程来"收尸"。 进程状态机的变化 原来进程只有三个状态:UNUSED、READY、RUNNING。这一章加两个: UNUSED → READY → RUNNING ↓ exit() ZOMBIE ← 已退出,等父进程 wait ↑ 唤醒 BLOCKED ← 父进程 wait 时挂起 调度器只挑 READY 的进程运行,ZOMBIE 和 BLOCKED 自然就不会被调度到,不需要改调度器的逻辑。 exit 和 wait 的实现思路 exit 做三件事: 把退出码存到进程表项,状态改为 ZOMBIE 如果父进程正在 BLOCKED 等待,把它改回 READY(唤醒) 切回内核栈和内核页表,hlt 循环等待被回收 wait 做的事: 扫描进程表,找有没有自己的子进程且状态是 ZOMBIE 找到了:读退出码,把它设为 UNUSED,返回退出码 没找到但有活着的子进程:挂起等待(ring3)或返回 -2 让调用方重试(ring0) 没有子进程:返回 -1 parent_pid 需要在 exec / fork 时记下来,这样 exit 才知道该唤醒谁,wait 才知道哪些进程是自己的子进程。 ...

May 13, 2026 · 2 min · 大飞
京ICP备14031575号-3