当前位置: 首页 > 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.rkmt.cn/news/1496653.html

相关文章:

  • 北京看守所律师事务所:驻所法律服务与常规代理有何本质区别? - 品牌2026
  • 丽水缙云县黄金回收指南:避开陷阱,多拿上千元 - 专业黄金回收
  • 细说KISS、YAGNI原则
  • 论文精读:基于GIS与地理探测器的西南喀斯特石漠化空间分布及驱动因子分析
  • 制造业领域:2026年值得关注的手推式/驾驶式/全自动工业扫地机制造商 - 企业推荐官【官方】
  • 2026义乌UV双喷服务机构整理推荐 - 奔跑123
  • 通诚无忧-通辽信息港信息平台运营策略:打造用户喜爱的通辽市本地服务社区
  • Playwright视觉比较(图片比对测试)
  • 第76篇 | HarmonyOS 保险箱详情页:私密照片如何浏览、恢复和导出
  • Kotlin单表达式函数在安卓开发中的精简艺术
  • 手把手教你用MATLAB复现圆柱绕流POD分解:从Brunton的代码到自己的流场图
  • AgentWatch MCP 服务说明文档
  • 基于 LlamaIndex + DeepSeek + Streamlit 搭建智能问答系统
  • 2026最新渭南市黄金回收价格一览表 回收避坑攻略靠谱商家推荐 - 余生黄金回收
  • UVM源码探秘:start_item的sequencer参数怎么用?解锁更灵活的sequence驱动方式
  • 10kV配网故障识别:波形分析全攻略
  • 【国产电脑python编译器配置】麒麟V10系统anaconda配置pycharm
  • 人工智能专业术语详解(I)
  • Vue3自定义指令实战:从拖拽到权限按钮,3个真实项目案例手把手教学
  • STM32F4实战:5分钟搞定CANopen快速SDO通信,读取节点数据就这么简单
  • 云南大学考研辅导班正规机构,全维度榜单推荐 - 推荐评测师
  • 弹窗交互:AlertDialog与CustomDialog的创建与关闭(11)
  • 【提示词工程】提示词工程笔记:从核心思想到实战代码
  • Got timeout reading communication packets解决方法
  • 微信投票小程序怎么用丨图文视频投票制作全过程(海投票实时更新) - 微信投票小程序
  • 告别编译焦虑!Windows 10下用LLVM-MinGW和Ninja一键搞定OLLVM-14.x(附成品下载)
  • 别再截图了!用Altium Designer 23原生功能导出PCB高清丝印图,5分钟搞定SW贴图素材
  • 通化黄金回收2026大盘价结算无套路攻略 - 润富黄金回收
  • 云南研学旅行包车公司排行:5家合规靠谱服务商盘点 - 奔跑123
  • 不只是混淆:手把手教你将OLLVM-14.x集成到Android Studio NDK,打造专属加固工具链