Master通过监听SIGCHLD信号获知Worker退出,再调用waitpid获取真实退出状态;关注退出原因(如SIGSEGV异常终止需拉起新进程),而非退出码本身。

Master 进程通过监听 SIGCHLD 信号来感知 Worker 进程的退出,并不是直接“读取状态码”,而是借助内核通知机制获知子进程已终止,再主动调用系统接口获取其真实退出状态(包括退出码、是否被信号终止等)。
为什么是 SIGCHLD 而不是轮询?
Linux 内核规定:当任意子进程终止(无论正常 exit 或被信号杀死),内核会自动向其父进程发送 SIGCHLD。这是一种异步、轻量、可靠的事件通知方式。Master 不需要持续检查每个 Worker 是否还活着,避免了资源浪费和延迟。
收到 SIGCHLD 后,Master 实际做了什么?
Master 的信号处理函数 ngx_signal_handler 捕获到 SIGCHLD 后,并不立即清理,而是设置一个标志位 ngx_reap = 1,并在主循环中后续调用 ngx_process_get_status() —— 这才是真正获取退出状态的核心步骤:
- 它遍历内部进程表 ngx_processes,对每个标记为 exited 或 exiting 的 Worker,调用 waitpid(pid, &status, WNOHANG)
- WNOHANG 表示非阻塞:如果子进程还没完成退出收尾(如资源释放未完),就跳过,不卡住 Master
- 从 status 中解析出实际退出信息:WIFEXITED(status) 判断是否正常退出,WEXITSTATUS(status) 提取退出码;WIFSIGNALED(status) 判断是否被信号杀死,WTERMSIG(status) 获取终止信号编号
- 根据结果更新该 Worker 在进程表中的状态字段(如 exited=1、status=xxx),供后续 ngx_reap_children 统一回收
退出状态码的实际用途
Master 并不依赖退出码做业务决策(比如“退出码 1 就重启,0 就不重启”),而是重点关注退出原因是否异常:
- 若 Worker 因 SIGSEGV、SIGABRT 等致命信号退出(WTERMSIG(status) ∈ {11,6,...}),Master 通常会记录错误日志,并可能触发自动拉起新 Worker(取决于配置和当前负载)
- 若因 SIGQUIT 或 SIGTERM 正常退出(WIFEXITED(status) && WEXITSTATUS(status)==0),Master 视为优雅终止,只清理资源,不额外告警
- 退出码本身一般不透传给运维或监控系统;真正用于可观测性的,是 Master 日志中记录的信号名、Worker PID、以及是否触发了 respawn
关键点小结
SIGCHLD 是内核发给 Master 的“有子进程结束了”的提示单,不是状态报告本身;真正的退出状态(含状态码)必须由 Master 主动调用 waitpid 获取;Master 关注的是“怎么退的”,而不是“退成几”,异常退出才触发干预逻辑。

















