LoginSignup
37
37

More than 5 years have passed since last update.

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

Last updated at Posted at 2013-10-02

前回

nginxソースコードリーディング その0〜まえがき〜

リビジョン

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

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

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

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

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

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が呼ばれるので次はこの関数の中を見ていく。以下のように冒頭でシグナルのブロック設定を行なっている。

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

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

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がその入口である。

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を呼び出す。

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プロセスを生成する。

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〜イベント駆動エンジン〜

37
37
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
37
37