1 定义
ngx_init_signals 函数 定义在 ./nginx-1.24.0/src/os/unix/ngx_process.c
ngx_int_tngx_init_signals(ngx_log_t*log){ngx_signal_t*sig;structsigactionsa;for(sig=signals;sig->signo!=0;sig++){ngx_memzero(&sa,sizeof(structsigaction));if(sig->handler){sa.sa_sigaction=sig->handler;sa.sa_flags=SA_SIGINFO;}else{sa.sa_handler=SIG_IGN;}sigemptyset(&sa.sa_mask);if(sigaction(sig->signo,&sa,NULL)==-1){#if(NGX_VALGRIND)ngx_log_error(NGX_LOG_ALERT,log,ngx_errno,"sigaction(%s) failed, ignored",sig->signame);#elsengx_log_error(NGX_LOG_EMERG,log,ngx_errno,"sigaction(%s) failed",sig->signame);returnNGX_ERROR;#endif}}returnNGX_OK;}
ngx_init_signals 函数的作用是 初始化 Nginx 进程的信号处理机制。 它遍历预定义的信号列表,通过 sigaction 系统调用为每个信号注册自定义处理函数 确保进程能够响应如优雅退出、配置重载等控制指令。 若注册失败,在生产环境下会直接导致启动终止。
2 详解
1 函数签名
ngx_int_tngx_init_signals(ngx_log_t*log)
返回值 NGX_OK(0):表示信号初始化成功。 NGX_ERROR( -1):表示初始化过程中出现严重错误,导致 Nginx 无法继续启动。
参数 Nginx 自定义的日志对象结构体 在 sigaction 调用失败时,需要向错误日志写入记录
2 逻辑流程
1 局部变量 2 遍历 注册信号处理函数 3 返回成功
1 局部变量
{ngx_signal_t*sig;structsigactionsa;
2 遍历 注册信号处理函数
for(sig=signals;sig->signo!=0;sig++){ngx_memzero(&sa,sizeof(structsigaction));if(sig->handler){sa.sa_sigaction=sig->handler;sa.sa_flags=SA_SIGINFO;}else{sa.sa_handler=SIG_IGN;}sigemptyset(&sa.sa_mask);if(sigaction(sig->signo,&sa,NULL)==-1){#if(NGX_VALGRIND)ngx_log_error(NGX_LOG_ALERT,log,ngx_errno,"sigaction(%s) failed, ignored",sig->signame);#elsengx_log_error(NGX_LOG_EMERG,log,ngx_errno,"sigaction(%s) failed",sig->signame);returnNGX_ERROR;#endif}}
#1 sig = signals signals 是 Nginx 定义的全局静态数组,类型为 ngx_signal_t。 该结构体包含三个成员:信号编号 signo、信号名字符串 signame 和信号处理函数指针 handler。 初始化指针指向数组首元素。 sig->signo != 0 循环继续条件。 数组最后一个元素的 signo 成员被刻意设置为 0 这是一个常见的哨兵值技巧 sig++ 指针向后移动一个 ngx_signal_t 结构体的大小,指向下一个待处理的信号。
#2 清空结构体内存 struct sigaction sa 是在循环外部栈上分配的局部变量。 每次迭代开始必须将其内容归零。 避免残留的垃圾信息影响后续操作
#3 根据配置选择信号处理行为
#3-1 if (sig->handler) 分支(自定义处理): sa.sa_sigaction = sig->handler; sigaction 结构体内含一个共用体。 当标志位包含 SA_SIGINFO 时, 内核调用的是 sa_sigaction 指向的函数(三参数形式),而不是 sa_handler。 这里填入的是 Nginx 内部的信号处理函数(如 ngx_signal_handler)。 sa.sa_flags = SA_SIGINFO; 告诉内核使用扩展信号处理器。 这使得 Nginx 能够接收到发送者 PID、错误地址等额外上下文信息(siginfo_t),
#3-2 else 分支(显式忽略): sa.sa_handler = SIG_IGN; 如果 sig->handler 为 NULL, Nginx 不希望接收该信号。此时直接使用标准库定义的忽略宏 SIG_IGN。 此处未设置 SA_SIGINFO 标志,因此内核只会调用传统的单参数函数(或执行忽略动作)。
#4 初始化信号掩码 将信号集初始化为空集 这意味着在运行此信号的处理函数期间,不自动阻塞任何其他信号 Nginx 之所以这样做,是因为其信号处理函数设计得极短且可重入
#5 执行系统调用注册信号 sigaction:POSIX 标准的系统调用,用于改变进程对特定信号的处理行为 参数 1:sig->signo —— 要操作的信号编号(如 SIGTERM 对应的 15)。 参数 2:&sa —— 指向新动作结构体的指针。 参数 3:NULL —— 不保存旧的处理动作。 返回值检查: 返回 -1 表示失败(如信号编号无效、内核资源不足)。 若成功,该信号的新处理方式已在内核进程描述符中生效。
#6 错误处理 记录日志 返回错误状态码
3 返回成功
returnNGX_OK;}