nginx信号处理核心是ngx_signal_handler函数,通过sigaction注册异步响应SIGHUP等信号,仅设标志位而不执行耗时操作,真实行为由主循环检查标志后调用对应函数完成。

nginx 的信号处理核心在 ngx_signal_handler 函数,它不是靠轮询或线程监听,而是通过标准 Unix 信号机制(sigaction)注册后由内核异步触发。该函数运行在主进程上下文中,直接响应如 SIGHUP、SIGUSR1、SIGTERM 等关键信号,决定 nginx 是重载配置、重新打开日志,还是优雅退出。
信号注册阶段:主进程调用 ngx\_init\_signals 绑定 handler
nginx 启动初期,主进程执行 ngx_init_signals,对每个关注的信号(如 SIGHUP、SIGINT、SIGQUIT、SIGUSR1、SIGUSR2、SIGWINCH)调用 sigaction,将 ngx_signal_handler 设为处理函数,并设置 SA_RESTART 和 SA_NODEFER 标志。这意味着:
- 被中断的系统调用(如
accept、read)会自动重启,避免因信号导致连接阻塞 - 信号不会在 handler 执行期间被屏蔽,允许同类型信号重复递送(但实际中 nginx 通常只做一次响应)
- handler 运行时,所有工作进程仍正常处理请求,信号处理本身不阻塞服务
信号分发逻辑:ngx\_signal\_handler 解析信号并设标志位
ngx_signal_handler 不直接执行重载或退出动作,而是根据 signo 查找预定义的 ngx_signal_t 表,获取信号名、是否应忽略、是否需通知工作进程等元信息,然后:
- 打印日志,例如
"signal 1 (SIGHUP) received" - 设置全局标志位,如
ngx_reconfigure = 1(对应 SIGHUP)、ngx_quit = 1(对应 SIGQUIT) - 对需通知 worker 的信号(如
SIGUSR1),向所有工作进程发送相同信号;对仅主进程响应的(如SIGWINCH),则不转发
这种“仅设标志+延后处理”设计,避免在信号上下文中执行复杂操作(如文件 I/O、内存分配),符合异步信号安全(async-signal-safe)原则。
主循环中检查标志:事件循环驱动真实行为
真正执行 reload、quit 或 reopen 操作的位置不在信号 handler 内,而是在主进程的事件循环(ngx_master_process_cycle)中周期性检查这些标志:
- 发现
ngx_reconfigure == 1→ 调用ngx_reconfigure:fork 新 worker、加载新配置、逐步关停旧 worker - 发现
ngx_quit == 1→ 调用ngx_quit:向 worker 发送QUIT信号,等待其处理完当前请求后退出 - 发现
ngx_reopen == 1(来自 SIGUSR1)→ 调用ngx_reopen:重新打开所有日志文件句柄,支持日志切割
这种分离让信号处理极快返回,同时把耗时操作交给可控的主循环,兼顾实时性与稳定性。
工作进程的信号响应:轻量级 handler + 自身状态管理
工作进程也注册了 ngx_signal_handler,但行为更简单:只响应 QUIT、TERM、INT、USR1 等少数信号。例如收到 QUIT 时设 ngx_quit = 1,随后在自己的事件循环中检测并主动关闭监听套接字、停止接受新连接,完成 graceful shutdown。
注意:worker 不处理 SIGHUP —— 配置重载由主进程统一调度,worker 只负责按新配置启动或按旧配置退出。

















