前回
リビジョン
5411:5483d9e77b32
nginx起動
前回の最後に書いた通りmain関数からトップダウン的に読んでいく。なのでまずはmain関数を探す。
$ global -x main
main 202 src/core/nginx.c main(int argc, char *const *argv)
$
main関数はこんな感じで各コンポーネント(タイマー、正規表現エンジン、ログ、シグナル等)の初期化を行なっている。
int ngx_cdecl
main(int argc, char *const *argv)
{
・
・
ngx_debug_init();
・
・
ngx_time_init();
・
・
#if (NGX_PCRE)
ngx_regex_init();
#endif
・
・
log = ngx_log_init(ngx_prefix);
・
・
if (ngx_init_signals(cycle->log) != NGX_OK) {
return 1;
}
・
・
また、ポートのlistenはngx_init_cycleで行う。
cycle = ngx_init_cycle(&init_cycle);
より具体的にはngx_open_listening_socketsで行われる。
if (ngx_open_listening_sockets(cycle) != NGX_OK) {
goto failed;
}
このほかにも環境変数やコマンドライン引数等の情報をグローバル変数に保存している。そして最後に以下の分岐がある。
if (ngx_process == NGX_PROCESS_SINGLE) {
ngx_single_process_cycle(cycle);
} else {
ngx_master_process_cycle(cycle);
}
通常はngx_master_process_cycleが呼ばれるので次はこの関数の中を見ていく。以下のように冒頭でシグナルのブロック設定を行なっている。
sigemptyset(&set);
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));
if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"sigprocmask() failed");
}
nginxのmasterプロセスはこの後、workerプロセスと必要であればcache-managerプロセスを起動してsigsuspendでシグナルが送られてくるのを待つだけになる。nginxをシグナルで制御する方法について解説したページが公式サイトにあるので詳しくはここを参照。簡単に言うとnginxのプロセスをまとめて終了させたり、緩やかな(graceful)再起動、無停止バージョンアップデートなどができる。
ところでnginxはプロセス名をmasterやworker、cache-managerとで別にするためプロセス名を置き換えるのだが、そのための処理もこのあたりで行われる。
size = sizeof(master_process);
for (i = 0; i < ngx_argc; i++) {
size += ngx_strlen(ngx_argv[i]) + 1;
}
title = ngx_pnalloc(cycle->pool, size);
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);
続いてworkerプロセスを起動させる処理(この処理の時点ではまだsigsuspendに入っていない)について見ていこう。ngx_start_worker_processesがその入口である。
ngx_start_worker_processes(cycle, ccf->worker_processes,
NGX_PROCESS_RESPAWN);
ngx_start_cache_manager_processes(cycle, 0);
以下のようにworker_processesの数だけngx_spawn_processを呼び出す。
for (i = 0; i < n; i++) {
ngx_spawn_process(cycle, ngx_worker_process_cycle,
(void *) (intptr_t) i, "worker process", type);
・
・
}
この関数の中でioctlやfcntlでソケットの各種設定を行った後、masterプロセスからforkしてworkerプロセスを生成する。
pid = fork();
switch (pid) {
case -1:
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"fork() failed while spawning \"%s\"", name);
ngx_close_channel(ngx_processes[s].channel, cycle->log);
return NGX_INVALID_PID;
case 0:
ngx_pid = ngx_getpid();
proc(cycle, data);
break;
default:
break;
}
procはngx_spawn_processの第二引数ngx_worker_process_cycleでこれがworkerプロセスのメインループになる。最後にmasterプロセスはすべてのworkerプロセスを起動した後、sigsuspendでシグナル待ちの状態になる。
というわけでnginxが起動してsingle-maseter & multi-workersが起動するところまで読んだ。今回はここまで。