当前位置: 首页 > news >正文

ngx_signal_worker_processes

1 定义

ngx_signal_worker_processes 函数 定义在 ./nginx-1.24.0/src/os/unix/ngx_process_cycle.c
staticvoidngx_signal_worker_processes(ngx_cycle_t*cycle,intsigno){ngx_int_ti;ngx_err_terr;ngx_channel_tch;ngx_memzero(&ch,sizeof(ngx_channel_t));#if(NGX_BROKEN_SCM_RIGHTS)ch.command=0;#elseswitch(signo){casengx_signal_value(NGX_SHUTDOWN_SIGNAL):ch.command=NGX_CMD_QUIT;break;casengx_signal_value(NGX_TERMINATE_SIGNAL):ch.command=NGX_CMD_TERMINATE;break;casengx_signal_value(NGX_REOPEN_SIGNAL):ch.command=NGX_CMD_REOPEN;break;default:ch.command=0;}#endifch.fd=-1;for(i=0;i<ngx_last_process;i++){ngx_log_debug7(NGX_LOG_DEBUG_EVENT,cycle->log,0,"child: %i %P e:%d t:%d d:%d r:%d j:%d",i,ngx_processes[i].pid,ngx_processes[i].exiting,ngx_processes[i].exited,ngx_processes[i].detached,ngx_processes[i].respawn,ngx_processes[i].just_spawn);if(ngx_processes[i].detached||ngx_processes[i].pid==-1){continue;}if(ngx_processes[i].just_spawn){ngx_processes[i].just_spawn=0;continue;}if(ngx_processes[i].exiting&&signo==ngx_signal_value(NGX_SHUTDOWN_SIGNAL)){continue;}if(ch.command){if(ngx_write_channel(ngx_processes[i].channel[0],&ch,sizeof(ngx_channel_t),cycle->log)==NGX_OK){if(signo!=ngx_signal_value(NGX_REOPEN_SIGNAL)){ngx_processes[i].exiting=1;}continue;}}ngx_log_debug2(NGX_LOG_DEBUG_CORE,cycle->log,0,"kill (%P, %d)",ngx_processes[i].pid,signo);if(kill(ngx_processes[i].pid,signo)==-1){err=ngx_errno;ngx_log_error(NGX_LOG_ALERT,cycle->log,err,"kill(%P, %d) failed",ngx_processes[i].pid,signo);if(err==NGX_ESRCH){ngx_processes[i].exited=1;ngx_processes[i].exiting=0;ngx_reap=1;}continue;}if(signo!=ngx_signal_value(NGX_REOPEN_SIGNAL)){ngx_processes[i].exiting=1;}}}
ngx_signal_worker_processes 函数是 Nginx 主进程中用于向所有工作进程(及辅助进程)分发信号的函数。 它优先通过进程间通道发送优雅的控制命令(如退出、重新打开日志), 在通道不可用或失败时则使用 `kill` 系统调用直接发送信号, 并根据发送结果更新进程的退出状态。

2 详解

1 函数签名

staticvoidngx_signal_worker_processes(ngx_cycle_t*cycle,intsigno)
返回值 函数不返回任何值
参数1 ngx_cycle_t *cycle 当前运行周期上下文环境
参数2 int signo 表示要发送的信号编号

2 逻辑流程

1 命令准备 1 不支持传递文件描述符,命令置为 0,表示没有有效命令 2 支持传递文件描述符,根据输入信号设置对应的命令 2 遍历所有进程发送命令 1 跳过无需发送命令的进程 2 命令有效,通过通道发送命令 3 命令无效或通道发送命令失败,通过 kill 发送信号

1 命令准备

{ngx_int_ti;ngx_err_terr;ngx_channel_tch;
局部变量声明

ngx_memzero(&ch,sizeof(ngx_channel_t));
将 ch 结构体所有字段清零

若系统不支持通过通道传递文件描述符 (定义了 NGX_BROKEN_SCM_RIGHTS), 则编译以下代码块。
#if(NGX_BROKEN_SCM_RIGHTS)ch.command=0;
直接将通道命令置为 0,表示没有有效命令。 逻辑: 既然系统不支持通道传递描述符, 那么通道命令机制也不可用, 因此强制命令为 0,后续将跳过通道发送,只使用 kill 信号。

支持传递文件描述符
#elseswitch(signo){casengx_signal_value(NGX_SHUTDOWN_SIGNAL):ch.command=NGX_CMD_QUIT;break;casengx_signal_value(NGX_TERMINATE_SIGNAL):ch.command=NGX_CMD_TERMINATE;break;casengx_signal_value(NGX_REOPEN_SIGNAL):ch.command=NGX_CMD_REOPEN;break;default:ch.command=0;}#endif
根据输入信号选择对应的通道命令
优雅关闭信号(通常为 SIGQUIT): 通道命令设为 NGX_CMD_QUIT, 工作进程收到后会优雅关闭。
强制终止信号(通常为 SIGINT 或 SIGTERM): 通道命令设为 NGX_CMD_TERMINATE, 工作进程收到后快速退出。
重新打开日志文件信号(通常为 SIGUSR1): 通道命令设为 NGX_CMD_REOPEN, 工作进程收到后重新打开日志文件。
其他信号: 不设置命令(0 表示无效), 因为其他信号不需要通过通道传递特殊语义。

ch.fd=-1;
将通道消息中的文件描述符字段设为 -1(无效值)。 本次通知不传递任何文件描述符,显式标记为无效,接收方应忽略该字段。

2 遍历所有进程发送命令

for(i=0;i<ngx_last_process;i++){
遍历全局进程数组 ngx_processes。 ngx_last_process 是当前管理的进程总数。 对每一个记录在案的进程尝试发送信号。

ngx_log_debug7(NGX_LOG_DEBUG_EVENT,cycle->log,0,"child: %i %P e:%d t:%d d:%d r:%d j:%d",i,ngx_processes[i].pid,ngx_processes[i].exiting,ngx_processes[i].exited,ngx_processes[i].detached,ngx_processes[i].respawn,ngx_processes[i].just_spawn);
输出当前进程的详细状态到调试日志

if(ngx_processes[i].detached||ngx_processes[i].pid==-1){continue;}
过滤已分离或 PID 无效的进程。 分离的进程已脱离主进程管理; PID 为 -1 表示进程不存在。 这两种情况均无需也无法发送信号,直接跳过。 避免向无效目标发送信号

if(ngx_processes[i].just_spawn){ngx_processes[i].just_spawn=0;continue;}
跳过刚刚生成(fork)的进程,并清除该标志。 刚 fork 出的进程可能还未完成信号处理函数的设置, 立即发送信号可能造成竞态或未定义行为。 跳过一次,下次调用本函数时标志已清除,可以正常发送。

if(ngx_processes[i].exiting&&signo==ngx_signal_value(NGX_SHUTDOWN_SIGNAL)){continue;}
避免对已经在优雅关闭的进程重复发送 SIGQUIT。 如果进程已标记为 exiting(说明已收到退出指令),且本次信号仍是优雅关闭,则无需再次通知。 但若本次是强制终止等信号,则仍会穿透此检查继续处理(因为可能需要强制结束卡住的进程)。 意义:减少不必要的信号发送,同时允许强制信号覆盖正在优雅退出的进程。

if(ch.command){if(ngx_write_channel(ngx_processes[i].channel[0],&ch,sizeof(ngx_channel_t),cycle->log)==NGX_OK){if(signo!=ngx_signal_value(NGX_REOPEN_SIGNAL)){ngx_processes[i].exiting=1;}continue;}}
检查通道命令是否有效(非零)。 如果有效,优先尝试通过进程间通道发送命令, 这比直接 kill 更优雅。
调用 ngx_write_channel 将封装好的命令消息通过 socket 发送给目标进程。 参数: ngx_processes[i].channel[0] 是主进程端与该进程通信的 socket 文件描述符; ch 为消息内容; cycle->log 用于记录错误。 返回值:成功返回 NGX_OK。
若通道发送成功,且信号不是重新打开日志(NGX_REOPEN_SIGNAL), 则将进程状态标记为 exiting = 1(正在退出)。 然后 continue 跳过 kill 操作,处理下一个进程。 重新打开日志并不导致进程退出,因此不设 exiting 标志。 其他信号(关闭、终止)都会令进程最终退出,设置标志以跟踪其退出状态。 意义:精确维护进程生命周期状态,为后续回收子进程提供依据。

ngx_log_debug2(NGX_LOG_DEBUG_CORE,cycle->log,0,"kill (%P, %d)",ngx_processes[i].pid,signo);
记录即将对该 PID 使用 kill 发送信号的调试日志。 当通道命令不可用或发送失败时,会走到这里使用传统信号方式

if(kill(ngx_processes[i].pid,signo)==-1){err=ngx_errno;ngx_log_error(NGX_LOG_ALERT,cycle->log,err,"kill(%P, %d) failed",ngx_processes[i].pid,signo);if(err==NGX_ESRCH){ngx_processes[i].exited=1;ngx_processes[i].exiting=0;ngx_reap=1;}continue;}
调用 kill 系统调用向目标进程发送信号。 直接发送原始信号值 signo。 成功返回 0,失败返回 -1 并设置 errno。 意义:作为通道不可用或失败时的后备方案,保证信号最终能被传递。
若 kill 失败,保存错误码并记录 ALERT 级别日志,包含 PID 和信号编号。
如果错误原因是 ESRCH(进程不存在), 则更新进程状态为已退出 (exited = 1), 清除 exiting 标志,并设置全局 ngx_reap = 1,通知主事件循环进行回收。 逻辑:进程已意外终止,主进程需要尽快获知并清理子进程资源。 意义:自动处理子进程异常退出,避免僵尸进程,保证进程表状态准确。
kill 失败后跳过后续状态设置(因为进程未收到信号), 继续处理下一个进程。

if(signo!=ngx_signal_value(NGX_REOPEN_SIGNAL)){ngx_processes[i].exiting=1;}}}
如果 kill 发送成功,且信号不是重新打开日志, 则同样将进程标记为 exiting = 1。 与通道发送成功时的状态更新逻辑完全一致,保持行为统一。 意义:无论通过哪种方式发送退出信号,都能正确记录进程即将退出的状态。
http://www.jsqmd.com/news/984911/

相关文章:

  • 第二章 ICEF核心知识解读 第三节 ICEF对AI推理能力的系统性增强:机制、效果与深层价值
  • 2026 合肥高端包包优选榜单 包河靠谱交易门店汇总 - 开心测评
  • Vue 布局方案管理实战:拖拽面板位置保存与多方案切换完整指南
  • 计算机毕业设计之基于大数据的食物营养分析可视化平台
  • 深入解析机器人软件开发中的PID控制:聚焦抗积分饱和优化策略
  • 传统企业 AI 落地,不是买工具,而是重构信息流
  • 北京看守所律师事务所:驻所法律服务与常规代理有何本质区别? - 品牌2026
  • 第八阶段:工程化、质量管控与高级拓展(136天),Vue项目监控:接入Sentry实现前端异常上报+错误定位+告警通知
  • 丽水缙云县黄金回收指南:避开陷阱,多拿上千元 - 专业黄金回收
  • Java博客写出你的故事,上头条拿大奖,别让才华睡大觉
  • 把专业知识装进7×24的AI盒子:波街智才市场的设计逻辑
  • 南京婚纱照怎么选?麦田影像教你拍出专属风格 - 速递信息
  • 论文精读:基于GIS与地理探测器的西南喀斯特石漠化空间分布及驱动因子分析
  • 【教学类-160-52】20260531 AI视频培训-练习052“豆包AI视频《海边跳舞少女》豆包图片风格:马蒂斯
  • 细说KISS、YAGNI原则
  • 制造业领域:2026年值得关注的手推式/驾驶式/全自动工业扫地机制造商 - 企业推荐官【官方】
  • 第76篇 | HarmonyOS 保险箱详情页:私密照片如何浏览、恢复和导出
  • 2026义乌UV双喷服务机构整理推荐 - 奔跑123
  • 通诚无忧-通辽信息港信息平台运营策略:打造用户喜爱的通辽市本地服务社区
  • Kotlin单表达式函数在安卓开发中的精简艺术
  • MySQL(三):库操作与表操作
  • 大理黄金回收2026全流程高价避坑攻略 - 润富黄金回收
  • 自流平材料在现代装修设计中的创新应用及魅力解析
  • Playwright视觉比较(图片比对测试)
  • 伺服电机仿真(7):非线性因素的建模
  • 手把手教你用MATLAB复现圆柱绕流POD分解:从Brunton的代码到自己的流场图
  • 大医精诚·孙思邈
  • /etc/passwd和/etc/shadow区别?用户信息与密码哈希分工详解
  • 2026年实测:各类大赛人气投票链接生成方法,3分钟搞定(免费+强防刷) - 微信投票小程序
  • Linux驱动程序机制