PHP-FPM中-D命令的实现
众所周知,php-fpm是fastcgi的管理程序,环境部署中我们使用php-fpm -D
来启动fpm进程,从而监听9000端口来处理nginx转发过来的request任务。关于fpm的启动之后也准备梳理一篇,本文主要是说一下 -D 这个命令,既而通过这个命令研究下在Linux下如何编写daemon进程。
什么是Daemon进程
Daemon进程是运行在后台的一种进程,它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。它不需要用户输入就能运行而且提供某种服务,不是对整个系统就是对某个用户程序提供服务。
一个守护进程的父进程是init进程,因为它真正的父进程在fork出子进程后就先于子进程exit退出了,所以它是一个由init继承的孤儿进程。守护进程是非交互式程序,没有控制终端,所以任何输出,无论是向标准输出设备stdout还是标准出错设备stderr的输出都需要特殊处理。
关于Daemon进程的一些原理
Linux中的进程与控制终端,登录会话和进程组之间的关系
进程属于一个进程组,进程组号(GID)就是进程组长的进程号(PID)。登录会话可以包含多个进程组。这些进程组共享一个控制终端。这个控制终端通常是创建进程的登录终端。
控制终端,登录会话和进程组通常是从父进程继承下来的。我们的目的就是要摆脱它们,使之不受它们的影响。
如何实现
关于如何实现?一般有几个步骤需要处理:
- fork()一个子进程继续执行父进程的任务,同时将父进程停止。这样就使得你的进程从控制端进入后台。
- 脱离控制终端,登录会话和进程组。调用setsid()使子进程成为会话组长。
- 关闭父进程打开的文件描述符。
- 处理SIGCHLD信号。
这4步中上面两步是必须的,后面是一般根据需要会需要处理的。
PHP-FPM的实现
在fpm中实现daemon的方法与上述一致,最后我们通过对fpm源码的跟踪来看一下具体实现的例子。(代码有删减)
一切从启动开始
/sapi/fpm/fpm/fpm_main.c
int main(int argc, char *argv[])
{
// 接收到-D参数,设置以daemon模式init fpm
while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
switch (c) {
case 'D': /* daemonize */
force_daemon = 1;
break;
}
}
if (0 > fpm_init(argc, argv, fpm_config ? fpm_config : CGIG(fpm_config), fpm_prefix, fpm_pid, test_conf, php_allow_to_run_as_root, force_daemon, force_stderr)