nginxソースコードリーディング その1〜nginx起動〜

# 前回

[nginxソースコードリーディング その0〜まえがき〜](http://qiita.com/cubicdaiya/items/e1fe4c991086f320353a)

# リビジョン

5411:5483d9e77b32

# nginx起動

前回の最後に書いた通りmain関数からトップダウン的に読んでいく。なのでまずはmain関数を探す。


```sh
$ global -x main
main              202 src/core/nginx.c main(int argc, char *const *argv)
$
```

main関数はこんな感じで各コンポーネント(タイマー、正規表現エンジン、ログ、シグナル等)の初期化を行なっている。

```c
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で行う。

```c:core/nginx.c(main)
    cycle = ngx_init_cycle(&init_cycle);
```

より具体的にはngx_open_listening_socketsで行われる。

```c:core/ngx_cycle.c(ngx_init_cycle)
    if (ngx_open_listening_sockets(cycle) != NGX_OK) {
        goto failed;
    }
```

このほかにも環境変数やコマンドライン引数等の情報をグローバル変数に保存している。そして最後に以下の分岐がある。

```c:core/nginx.c(main)
    if (ngx_process == NGX_PROCESS_SINGLE) {
        ngx_single_process_cycle(cycle);

    } else {
        ngx_master_process_cycle(cycle);
    }
```

通常はngx_master_process_cycleが呼ばれるので次はこの関数の中を見ていく。以下のように冒頭でシグナルのブロック設定を行なっている。

```c:os/unix/ngx_process_cycle.c(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をシグナルで制御する方法について解説した[ページ](http://nginx.org/en/docs/control.html)が公式サイトにあるので詳しくはここを参照。簡単に言うとnginxのプロセスをまとめて終了させたり、緩やかな(graceful)再起動、無停止バージョンアップデートなどができる。


ところでnginxはプロセス名をmasterやworker、cache-managerとで別にするためプロセス名を置き換えるのだが、そのための処理もこのあたりで行われる。

```c:os/unix/ngx_process_cycle.c(ngx_master_process_cycle)
    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がその入口である。

```c:os/unix/ngx_process_cycle.c(ngx_master_process_cycle)
    ngx_start_worker_processes(cycle, ccf->worker_processes,
                               NGX_PROCESS_RESPAWN);
    ngx_start_cache_manager_processes(cycle, 0);
```

以下のようにworker_processesの数だけngx_spawn_processを呼び出す。

```c:os/unix/ngx_process_cycle.c(ngx_start_worker_processes)
    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プロセスを生成する。

```c:os/unix/ngx_process.c(ngx_spawn_process)
    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が起動するところまで読んだ。今回はここまで。

# 次回(予定)

[nginxソースコードリーディング その2〜イベント駆動エンジン〜](http://qiita.com/cubicdaiya/items/f3460682cb908901a81d)