(nginx 源码系列六)--sigsuspend 的学习
twemproxy 的多进程改造计划中参考了 nginx 的设计,然而 nginx 有一段让我看不太明白。
这篇文章总结的很好
sigsuspend sigprocmask 函数的使用方法
sigsuspend 将新的信号集阻塞操作和 pause 操作组合在一起成为原子操作
做了以下的操作
设置新的 mask 阻塞当前进程;
收到信号,恢复原先 mask;
调用该进程设置的信号处理函数;
待信号处理函数返回后,sigsuspend 返回。
现在再来回顾一下我当时疑惑的代码段
1 | void |
首先初始化了一个空集 set, 往里面添加了信号形成阻塞的信号集合,然后运行 sigprocmask (SIG_BLOCK, &set, NULL) 阻塞这些信号
临界区(在 sigprocmask 之后和 sigsuspend 之前的代码)中如果出现了信号集的信号都会被阻塞
临界区之后运行的 sigsuspend (&set) 处理的信号集合是个空集
sigsuspend 将不会阻塞任何信号,如果在临界区中就发生信号会执行信号函数,否则就等待任何信号的发生,然后往下运行
这里要提一下临界区的代码,主要就是一句 ngx_start_worker_processes。
ngx_start_worker_processed 中会 fork 出子进程,每个子进程初始化时会调用 ngx_worker_process_init
1 | static void |
可以看到,在 fork 出进程后初始化,将继承的阻塞信号集设置为空集,也就是不在阻塞这些信号
这样做是怕 fork 前信号函数执行,例如在临界区执行 reload 信号执行函数,导致逻辑复杂化,现在的逻辑就很清晰,必须全部 fork 完毕以后才能 reload。
所以说 twemproxy 的多进程改造也应该学习这样的过程,把 fork 作为临界区来处理。
sigsuspend 在 APUE 这本圣经里面有个案例是当作同步来使用的。我觉得这个例子也很好。
我稍微补充了一下内容和书中有一些区别
1 | #include <stdio.h> |
父进程将等待子进程的信号,输出字串,随后发送子进程信号证明自己收到信号。
子进程输出字串,随后发送信号给父进程,然后等待父进程的信号后再次输出。
这样的同步方式使得字串永远按以下顺序输出不会乱序。
1 | [root@localhost.localdomain ~]# ./signal_test |
这种同步方式是很有启发性的。
例如子进程是父进程的一个阻塞操作的异步操作,父进程通过管道将处理的对象放入子进程的等待处理队列,子进程通过信号来告知父进程,已经全部处理完毕。
-
2015-05-19
由于 twemproxy 的多进程改造计划,所以对教科书一般的 nginx 的管理方式做了分析
nginx 的 - s 指令可以对进程执行多个命令。
这些命令由主进程接受信号然后在循环中对状态进行判断,然后通过 unix socket 或者信号的方式传达给子进程。
从代码里面可以看到如下状态。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15for()
{
if (delay) {}
sigsuspend();
ngx_time_update();
if (ngx_reap) {} //需要重启工作进程
if (!live && (ngx_terminate || ngx_quit)) {} //工作进程都结束,自己也设定了结束,那么退出
if (ngx_terminate) {} //强制退出状态
if (ngx_quit) {} //优雅退出状态
if (ngx_reconfigure) {} //配置热加载
if (ngx_restart) {} //重启(配置不变)
if (ngx_reopen) {} //重新打开日志
if (ngx_change_binary) {} //二进制文件改变
if (ngx_noaccept) {} //不再接受新连接
} -
2015-01-28
nginx 真是博大精深,最近写 fastdfs 的动态缩略图模块,刚好能有时间研究下,真是满心欢喜。
学习主要是靠两本书,其他的稍微搜搜也就能解惑了。
《Nginx 模块开发与架构解析》这个我看的电子 PDF
《Nginx 开发从入门到精通》这个有网页版本的,挺好的:
未找到相关的 Issues 进行评论
请联系 @tedcy 初始化创建