前言
在上一小节中,我们主要分析了master
进程的工作循环。本小结中,我们将看到nginx是如何创建worker进程的。在上一小节中分析master
进程的工作循环时,调用了ngx_start_worker_processes
函数,但是其内部调用的创建子进程的代码在ngx_spawn_process
中。
ngx_spawn_process
创建进程自然想到的就是调用fork
函数。ngx_spawn_process
函数中调用了fork
来完成对子进程的创建。
先分析一下该函数参数:
1. ngx_cycle_t *cycle
:给子进程的
ngx_spawn_proc_pt proc
:函数指针,定义为:typedef void (*ngx_spawn_proc_pt) (ngx_cycle_t *cycle, void *data);
。proc函数指针指向worker进程要执行的工作循环。void *data
:proc回调函数的参数char *name
:进程的名字,worker进程对应的是worker process
ngx_int_t respawn
:创建子进程时的属性,目前可以的取值为:
//子进程退出时,父进程不会再次创建(在创建cache loader process时使用)
#define NGX_PROCESS_NORESPAWN -1
//区别旧/新进程的标识位
#define NGX_PROCESS_JUST_SPAWN -2
//子进程异常退出时,父进程重新生成子进程的标识位
#define NGX_PROCESS_RESPAWN -3
//区别旧/新进程的标识位
#define NGX_PROCESS_JUST_RESPAWN -4
//热代码替换,父、子进程分离的标识位
#define NGX_PROCESS_DETACHED -5
ngx_spawn_process
的源码如下:
ngx_pid_t
ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
char *name, ngx_int_t respawn)
{
u_long on;
ngx_pid_t pid;
ngx_int_t s; //s为创建进程时,在全局数组ngx_processes的下标
//若大于0,则代表respawn下标对应的进程需要重启
if (respawn >= 0) {
s = respawn;
} else {
//在ngx_processes数组中找到一个空位用于启动进程
for (s = 0; s < ngx_last_process; s++) {
if (ngx_processes[s].pid == -1) {
break;
}
}
//NGX_MAX_PROCESSES宏定义为1024,代表可创建的进程最大数
if (s == NGX_MAX_PROCESSES) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
"no more than %d processes can be spawned",
NGX_MAX_PROCESSES);
return NGX_INVALID_PID;
}
}
//不是热代码替换
if (respawn != NGX_PROCESS_DETACHED) {
/* Solaris 9 still has no AF_LOCAL */
//调用socketpair为新的worker进程创建一对socket,后面会用于进程间通信
if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"socketpair() failed while spawning \"%s\"", name);
return NGX_INVALID_PID;
}
ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
"channel %d:%d",
ngx_processes[s].channel[0],
ngx_processes[s].channel[