一、说明
从默认的情况下分析,nginx启动之后会分别有一个master进程与一个worker进程

从上一章,了解到整个main函数的执行流程之后,我们就知道下面函数
ngx_master_process_cycle(cycle);
是启动master进程与worker进程的核心函数。
还有根据还是的知识,master进程与worker进程的职能分工入下

了解这些这后,我们继续深入的去看ngx_master_process_cycle 函数到底在做什么?
二、函数分析
开始的变量申明就先不讲了。
sigemptyset(&set);
set是一个sigset_t的数据结构,系统自带的。这里是将信号清空。
sigaddset(&set, SIGCHLD);
sigaddset(&set, SIGALRM);
sigaddset(&set, SIGIO);
sigaddset(&set, SIGINT);
sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL));
sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL));
sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL));
sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL));
sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL));
将SIGCHLD SIGALRM SIGIO等等信号,增加到&set中去。具体为什么这里设置了信号,后面又要清空掉,后面在讨论。
if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"sigprocmask() failed");
}
将&set数组里面的信息进行屏蔽。
sigemptyset(&set);
清空信号
size = sizeof(master_process);
for (i = 0; i < ngx_argc; i++) {
size += ngx_strlen(ngx_argv[i]) + 1;
}
在上文提到过,main函数在执行ngx_save_argv,将参数信息保存到ngx_argv数组里面,这样来设置size的大小,size为后面进程显示用。
title = ngx_pnalloc(cycle->pool, size);
if (title == NULL) {
/* fatal */
exit(2);
}
为title申请内存块,内存块大小是否大于最大的内存块,若大于则使用大块内存的分配。
p = ngx_cpymem(title, master_process, sizeof(master_process) - 1);
for (i = 0; i < ngx_argc; i++) {
*p++ = ' ';
p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size);
}
ngx_setproctitle(title);
设置title,nginx的作者为了性能也是拼了,一般我们写这个真不会写的这么复杂。类似可以看到如下这样的title
master process ./sbin/nginx
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
获取配置
ngx_start_worker_processes(cycle, ccf->worker_processes,
NGX_PROCESS_RESPAWN);
启动worker进程,worker进程的数量跟worker_processes设置的数量有关系。ngx_spawn_process函数组装创建逻辑,会循环调用多次。ngx_worker_process_cycle是worker进程处理事件,并且将accept事件和read、write事件分开队列进行处理。并且将进程创建的事件广播出去。这块后续会深入的去分析。//TODO
ngx_start_cache_manager_processes(cycle, 0);
启动的缓存模块,之后会生存这样一个进程,专门来处理。

在nginx.conf文件中中,配置了proxy_cache_path就会启动这个进程,如果没有配置就没有这个进程。具体内容后面再去讨论。//TODO
ngx_new_binary = 0;
delay = 0;
sigio = 0;
live = 1;
for ( ;; ) {
if (delay) {
if (ngx_sigalrm) {
sigio = 0;
delay *= 2;
ngx_sigalrm = 0;
}
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"termination cycle: %M", delay);
itv.it_interval.tv_sec = 0;
itv.it_interval.tv_usec = 0;
itv.it_value.tv_sec = delay / 1000;
itv.it_value.tv_usec = (delay % 1000 ) * 1000;
if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"setitimer() failed");
}
}
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend");
sigsuspend(&set);
ngx_time_update();
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"wake up, sigio %i", sigio);
if (ngx_reap) {
ngx_reap = 0;
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children");
live = ngx_reap_children(cycle);
}
if (!live && (ngx_terminate || ngx_quit)) {
ngx_master_process_exit(cycle);
}
if (ngx_terminate) {
if (delay == 0) {
delay = 50;
}
if (sigio) {
sigio--;
continue;
}
sigio = ccf->worker_processes + 2 /* cache processes */;
if (delay > 1000) {
ngx_signal_worker_processes(cycle, SIGKILL);
} else {
ngx_signal_worker_processes(cycle,
ngx_signal_value(NGX_TERMINATE_SIGNAL));
}
continue;
}
if (ngx_quit) {
ngx_signal_worker_processes(cycle,
ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
ngx_close_listening_sockets(cycle);
continue;
}
if (ngx_reconfigure) {
ngx_reconfigure = 0;
if (ngx_new_binary) {
ngx_start_worker_processes(cycle, ccf->worker_processes,
NGX_PROCESS_RESPAWN);
ngx_start_cache_manager_processes(cycle, 0);
ngx_noaccepting = 0;
continue;
}
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring");
cycle = ngx_init_cycle(cycle);
if (cycle == NULL) {
cycle = (ngx_cycle_t *) ngx_cycle;
continue;
}
ngx_cycle = cycle;
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,
ngx_core_module);
ngx_start_worker_processes(cycle, ccf->worker_processes,
NGX_PROCESS_JUST_RESPAWN);
ngx_start_cache_manager_processes(cycle, 1);
/* allow new processes to start */
ngx_msleep(100);
live = 1;
ngx_signal_worker_processes(cycle,
ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
}
if (ngx_restart) {
ngx_restart = 0;
ngx_start_worker_processes(cycle, ccf->worker_processes,
NGX_PROCESS_RESPAWN);
ngx_start_cache_manager_processes(cycle, 0);
live = 1;
}
if (ngx_reopen) {
ngx_reopen = 0;
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
ngx_reopen_files(cycle, ccf->user);
ngx_signal_worker_processes(cycle,
ngx_signal_value(NGX_REOPEN_SIGNAL));
}
if (ngx_change_binary) {
ngx_change_binary = 0;
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary");
ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv);
}
if (ngx_noaccept) {
ngx_noaccept = 0;
ngx_noaccepting = 1;
ngx_signal_worker_processes(cycle,
ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
}
}
一个无条件的循环,处理输入的信号,之前也说过,master进程就是专门来处理各种命令的。先对master进程处理信号这块进行解读。
三、总结
Nginx所有进程的启动都是在函数ngx_master_process_cycle中完成的,包括master进程、worker进程和Cache进程,整体代码上还是比较清晰的,还有对各个进程需要处理事件的,也在这个过程中做了定义,就是最后一块master进程的无条件循环出现在这里感觉上不是特别好看,不过也是比较容易懂的。