从零写OS(五十二):waitpid 阻塞、信号投递修复、ext2 间接块

这章修了三个基础性的问题,每一个都影响着内核能否正确支持 busybox 的日常使用。 waitpid:从轮询到真正阻塞 sh 执行命令时需要等子进程退出: int pid = fork(); if (pid == 0) { exec(...); } waitpid(pid, &status, 0); // 等子进程 原来的实现是 sti + hlt 轮询: while (1) { code = proc_wait(&child_pid); if (code != -2) break; sti(); hlt(); cli(); // 等定时器唤醒,再试 } 这有两个问题:1. 浪费 CPU,定时器每 10ms 唤醒一次,立刻又继续轮询;2. 多核下 AP 的调度时钟可能不触发 BSP 的 hlt,等待时间不稳定。 改为真正的阻塞:父进程把自己设为 PROC_BLOCKED,调度器不再调度它,直到子进程退出时主动唤醒: // SYS_WAIT4 int32_t code = proc_wait(&child_pid); if (code == -2) { current->wait_wstatus_va = a2; // 记住要写 wstatus 的用户地址 current->state = PROC_BLOCKED; // 挂起 return -EINTR; // 返回调度器 } 子进程退出时(proc_exit)唤醒父进程: if (ppid < MAX_PROCS && procs[ppid].state == PROC_BLOCKED) { procs[ppid].state = PROC_READY; // 唤醒 } 信号投递:不能直接写用户虚拟地址 信号处理时,内核需要把返回地址压到用户栈(user_rsp - 8)。原来直接写: ...

June 4, 2026 · 2 min · 大飞
京ICP备14031575号-3