从零写OS(二十四):signal 信号机制
到目前为止,进程只能顺序跑完,没有"被打断"的能力。按 Ctrl+C 没有反应,子进程崩溃父进程不知道,kill 命令更无从谈起。 这一章实现 signal——内核向进程发送异步通知的机制。 信号是什么 信号是一个整数编号,内核用它告诉进程"发生了某件事": 信号 编号 默认行为 SIGUSR1 10 终止 SIGKILL 9 终止(不可捕获) SIGTERM 15 终止 SIGCHLD 17 忽略 进程可以用 signal(sig, handler) 注册自定义处理函数,也可以接受默认行为。 关键:信号不立刻打断进程 信号发送时只是设置一个 pending 位,不立刻跳转。等进程下次从内核态返回用户态时,才检查并派发: SYS_KILL → pending_signals |= (1 << sig) syscall 处理完 → 准备 sysret ↓ 检查 pending_signals ↓ 有信号 → 操纵 user_rip/user_rsp → sysret 跳到 handler handler 执行完 ret → 回到原来被中断的位置 这和硬件中断不同——硬件中断可以在任意时刻打断 CPU,信号只在内核→用户的切换点才生效。 派发机制(trampoline) signal_dispatch 收到两个指针:内核栈上保存的 user_rip(原来准备 sysret 到的地址)和 user_rsp。它做的事: 1. user_rsp -= 8 2. *(user_rsp) = user_rip // 原返回地址压到用户栈 3. user_rip = handler_addr // sysret 改跳到 handler sysret 跳到 handler,handler 执行完 ret,弹出用户栈上的原 rip,回到 kill syscall 之后继续。 ...