nginx module和初始化流程

module

數(shù)據(jù)結(jié)構(gòu)

struct ngx_module_s {
    ngx_uint_t            ctx_index;//所屬模塊的索引
    ngx_uint_t            index;//全部模塊中的索引

    ngx_uint_t            spare0;
    ngx_uint_t            spare1;
    ngx_uint_t            spare2;
    ngx_uint_t            spare3;//保留

    ngx_uint_t            version;

    void                 *ctx;//具體模塊類型中的上下文
    ngx_command_t        *commands;//包含的命令
    ngx_uint_t            type;//是哪種模塊

    ngx_int_t           (*init_master)(ngx_log_t *log);//初始化master

    ngx_int_t           (*init_module)(ngx_cycle_t *cycle);//初始化module

    ngx_int_t           (*init_process)(ngx_cycle_t *cycle);//初始化服務(wù)
    ngx_int_t           (*init_thread)(ngx_cycle_t *cycle);//初始化線程
    void                (*exit_thread)(ngx_cycle_t *cycle);//退出線程
    void                (*exit_process)(ngx_cycle_t *cycle);//退出服務(wù)

    void                (*exit_master)(ngx_cycle_t *cycle);//退出master

    uintptr_t             spare_hook0;
    uintptr_t             spare_hook1;
    uintptr_t             spare_hook2;
    uintptr_t             spare_hook3;
    uintptr_t             spare_hook4;
    uintptr_t             spare_hook5;
    uintptr_t             spare_hook6;
    uintptr_t             spare_hook7;//保留
};

module的數(shù)據(jù)結(jié)構(gòu)特別的簡單就不單獨說了短荐,來看具體的啟動流程為后面的分析做準(zhǔn)備铣缠。

函數(shù)的入口在nginx.c里面的main函數(shù)

 ngx_debug_init();//調(diào)試初始化

    if (ngx_strerror_init() != NGX_OK) {//把系統(tǒng)的錯誤保存在ngx_sys_errlist
        return 1;
    }
    if (ngx_get_options(argc, argv) != NGX_OK) { //解析命令參數(shù)
        return 1;
    }

 if (ngx_show_version) {
        ngx_write_stderr("nginx version: " NGINX_VER_BUILD NGX_LINEFEED);

        if (ngx_show_help) {
            ngx_write_stderr(
                "Usage: nginx [-?hvVtTq] [-s signal] [-c filename] "
                             "[-p prefix] [-g directives]" NGX_LINEFEED
                             NGX_LINEFEED
                "Options:" NGX_LINEFEED
                "  -?,-h         : this help" NGX_LINEFEED
                "  -v            : show version and exit" NGX_LINEFEED
                "  -V            : show version and configure options then exit" //除了version外還可以顯示操作系統(tǒng)和configure階段等相關(guān)信息
                                   NGX_LINEFEED
                "  -t            : test configuration and exit" NGX_LINEFEED  //不啟動nginx進程恩伺,只是測試配置文件是否有錯誤
                "  -T            : test configuration, dump it and exit"
                                   NGX_LINEFEED
                "  -q            : suppress non-error messages "
                                   "during configuration testing" NGX_LINEFEED //通過-t測試配置文件是否錯誤的時候,nginx -t -q可以把error級別以下的日志不輸出的屏幕
                "  -s signal     : send signal to a master process: "
                                   "stop, quit, reopen, reload" NGX_LINEFEED
#ifdef NGX_PREFIX
                "  -p prefix     : set prefix path (default: "
                                   NGX_PREFIX ")" NGX_LINEFEED  //指定安裝目錄  
#else
                "  -p prefix     : set prefix path (default: NONE)" NGX_LINEFEED
#endif
                "  -c filename   : set configuration file (default: "
                                   NGX_CONF_PATH ")" NGX_LINEFEED //指定配置文件
                "  -g directives : set global directives out of configuration "
                                   "file" NGX_LINEFEED NGX_LINEFEED
                );
        }

        if (ngx_show_configure) {

#ifdef NGX_COMPILER
            ngx_write_stderr("built by " NGX_COMPILER NGX_LINEFEED);
#endif

#if (NGX_SSL)
            if (SSLeay() == SSLEAY_VERSION_NUMBER) {
                ngx_write_stderr("built with " OPENSSL_VERSION_TEXT
                                 NGX_LINEFEED);
            } else {
                ngx_write_stderr("built with " OPENSSL_VERSION_TEXT
                                 " (running with ");
                ngx_write_stderr((char *) (uintptr_t)
                                 SSLeay_version(SSLEAY_VERSION));
                ngx_write_stderr(")" NGX_LINEFEED);
            }
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
            ngx_write_stderr("TLS SNI support enabled" NGX_LINEFEED);
#else
            ngx_write_stderr("TLS SNI support disabled" NGX_LINEFEED);
#endif
#endif

            ngx_write_stderr("configure arguments:" NGX_CONFIGURE NGX_LINEFEED);
        }

        if (!ngx_test_config) {
            return 0;
        }
    }

    ngx_time_init(); //初始化nginx環(huán)境的當(dāng)前時間
#if (NGX_PCRE)
    ngx_regex_init();//初始化regex 主要是設(shè)置內(nèi)存函數(shù)
#endif
    ngx_pid = ngx_getpid();//獲取進程信息

/*
  這個時候還米有讀取配置文件,所以不知道日志的存放的位置赋兵,如果這個時候要記錄一些初始化的錯誤信息拢蛋,也需要一個存儲的位置桦他,所以就使用的默認(rèn)的
*/
    log = ngx_log_init(ngx_prefix);
    if (log == NULL) {
        return 1;
    }
#if (NGX_OPENSSL)
    ngx_ssl_init(log);
#endif

    /*
     * init_cycle->log is required for signal handlers and
     * ngx_process_options()
     */

//初始化init_cycle 然后分配內(nèi)存分配器
    ngx_memzero(&init_cycle, sizeof(ngx_cycle_t));
    init_cycle.log = log;
    ngx_cycle = &init_cycle;

    init_cycle.pool = ngx_create_pool(1024, log);
    if (init_cycle.pool == NULL) {
        return 1;
    }
    if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) {
        return 1;
    }
    if (ngx_process_options(&init_cycle) != NGX_OK) {//設(shè)置配置文件路徑
        return 1;
    }
    if (ngx_os_init(log) != NGX_OK) {//操作系統(tǒng)相關(guān)的初始化
        return 1;
    }
    /*
     * ngx_crc32_table_init() requires ngx_cacheline_size set in ngx_os_init()
     */

    if (ngx_crc32_table_init() != NGX_OK) {
        return 1;
    }
 if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) {
        return 1;
    }// 函數(shù)通過環(huán)境變量NGINX完成socket的繼承
    ngx_max_module = 0;
    for (i = 0; ngx_modules[i]; i++) {
        ngx_modules[i]->index = ngx_max_module++;
    }//設(shè)置module的index

 cycle = ngx_init_cycle(&init_cycle);//開始對cycle進行初始化

//進入到ngx_init_cycle函數(shù)
    ngx_timezone_update();

    /* force localtime update with a new timezone */

    tp = ngx_timeofday();
    tp->sec = 0;

    ngx_time_update();


    log = old_cycle->log;

  pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);//創(chuàng)建pool
    if (pool == NULL) {
        return NULL;
    }
    pool->log = log;

    cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t));//分配新的cycle內(nèi)存
    if (cycle == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }

    cycle->pool = pool;
    cycle->log = log;
    cycle->old_cycle = old_cycle;

    cycle->conf_prefix.len = old_cycle->conf_prefix.len;//配置信息拷貝
    cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix);
    if (cycle->conf_prefix.data == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }

    cycle->prefix.len = old_cycle->prefix.len;
    cycle->prefix.data = ngx_pstrdup(pool, &old_cycle->prefix);
    if (cycle->prefix.data == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }

    cycle->conf_file.len = old_cycle->conf_file.len;
    cycle->conf_file.data = ngx_pnalloc(pool, old_cycle->conf_file.len + 1);
    if (cycle->conf_file.data == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }
    ngx_cpystrn(cycle->conf_file.data, old_cycle->conf_file.data,
                old_cycle->conf_file.len + 1);

    cycle->conf_param.len = old_cycle->conf_param.len;
    cycle->conf_param.data = ngx_pstrdup(pool, &old_cycle->conf_param);
    if (cycle->conf_param.data == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }
//對路徑數(shù)組和打開文件列表的一些拷貝和初始化
   n = old_cycle->paths.nelts ? old_cycle->paths.nelts : 10;

    cycle->paths.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *));
    if (cycle->paths.elts == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }

    cycle->paths.nelts = 0;
    cycle->paths.size = sizeof(ngx_path_t *);
    cycle->paths.nalloc = n;

    /*
    // 這里都把內(nèi)存池給賦值給對象的內(nèi)存池屬性, 因為在內(nèi)存和資源管理方面谆棱,nginx委托內(nèi)存池統(tǒng)一管理快压, 這里可以通過具體的對象找到
    它用的內(nèi)存池對象, 方便實現(xiàn)內(nèi)存和資源方面的管理垃瞧。  
    */
    cycle->paths.pool = pool;


    if (ngx_array_init(&cycle->config_dump, pool, 1, sizeof(ngx_conf_dump_t))
        != NGX_OK)
    {
        ngx_destroy_pool(pool);
        return NULL;
    }

    if (old_cycle->open_files.part.nelts) {
        n = old_cycle->open_files.part.nelts;
        for (part = old_cycle->open_files.part.next; part; part = part->next) {
            n += part->nelts;
        }

    } else {
        n = 20;
    }

    if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t))
        != NGX_OK)
    {
        ngx_destroy_pool(pool);
        return NULL;
    }

//對共享內(nèi)存的個數(shù)拷貝
    if (old_cycle->shared_memory.part.nelts) {
        n = old_cycle->shared_memory.part.nelts;
        for (part = old_cycle->shared_memory.part.next; part; part = part->next)
        {
            n += part->nelts;
        }

    } else {
        n = 1;
    }

//對共享內(nèi)存初始化
    if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t)) 
        != NGX_OK)
    {
        ngx_destroy_pool(pool);
        return NULL;
    }

//對listening數(shù)組的初始化
 n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10;

    cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t));
    if (cycle->listening.elts == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }

    cycle->listening.nelts = 0;
    cycle->listening.size = sizeof(ngx_listening_t);
    cycle->listening.nalloc = n;
    cycle->listening.pool = pool;

    ngx_queue_init(&cycle->reusable_connections_queue);

    cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));//分配上下文信息的存儲數(shù)組蔫劣,對每一個模塊都進行了分配
    if (cycle->conf_ctx == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }

    if (gethostname(hostname, NGX_MAXHOSTNAMELEN) == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "gethostname() failed");
        ngx_destroy_pool(pool);
        return NULL;
    }

    /* on Linux gethostname() silently truncates name that does not fit */
    hostname[NGX_MAXHOSTNAMELEN - 1] = '\0';
    cycle->hostname.len = ngx_strlen(hostname);

    cycle->hostname.data = ngx_pnalloc(pool, cycle->hostname.len);
    if (cycle->hostname.data == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }

    ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len);

//調(diào)用所有的NGX_CORE_MODULE create_conf 分配配置存儲空間
    for (i = 0; ngx_modules[i]; i++) {
        if (ngx_modules[i]->type != NGX_CORE_MODULE) {
            continue;
        }

        module = ngx_modules[i]->ctx;

        if (module->create_conf) {
            rv = module->create_conf(cycle);
            if (rv == NULL) {
                ngx_destroy_pool(pool);
                return NULL;
            }
            
            cycle->conf_ctx[ngx_modules[i]->index] = rv;//保存在index對應(yīng)的位置
        }
    }

    senv = environ;

    ngx_memzero(&conf, sizeof(ngx_conf_t));
    /* STUB: init array ? */
    conf.args = ngx_array_create(pool, 10, sizeof(ngx_str_t));//用來保存沒一行的信息 
    if (conf.args == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }

    conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
    if (conf.temp_pool == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }


    //這時候的conf指向的是cycle
//配置conf的上下文環(huán)境
    conf.ctx = cycle->conf_ctx; //結(jié)合上一篇文章的配置尋找方法可以很清晰的發(fā)現(xiàn)是怎么回事啦
    conf.cycle = cycle;
    conf.pool = pool;
    conf.log = log;
    conf.module_type = NGX_CORE_MODULE;
    conf.cmd_type = NGX_MAIN_CONF;

    if (ngx_conf_param(&conf) != NGX_CONF_OK) { //這時候的conf指向的是cycle 對params進行解析
        environ = senv;
        ngx_destroy_cycle_pools(&conf);
        return NULL;
    }

    if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {//這時候的conf指向的是cycle 進入 cmd handler 模式 命令與handler一一對應(yīng) 然后進入模塊block再遞歸進行 進行配置解析
        environ = senv;
        ngx_destroy_cycle_pools(&conf);
        return NULL;
    }
//配置解析結(jié)束
 if (ngx_test_config && !ngx_quiet_mode) {//-t
        ngx_log_stderr(0, "the configuration file %s syntax is ok",
                       cycle->conf_file.data);
    }

    /*
    調(diào)用所有NGX—CORE—MODULE核心模塊的init_ conf方法。這一步驟的目的在于讓所有核心模塊在解析完配置項后可以做綜合性處理个从, 一般來說是對為被初始化的值進行下默認(rèn)值的配置
    */
    for (i = 0; ngx_modules[i]; i++) {
        if (ngx_modules[i]->type != NGX_CORE_MODULE) {
            continue;
        }

        module = ngx_modules[i]->ctx;

        if (module->init_conf) {
            if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index])
                == NGX_CONF_ERROR)
            {
                environ = senv;
                ngx_destroy_cycle_pools(&conf);
                return NULL;
            }
        }
    }
    if (ngx_process == NGX_PROCESS_SIGNALLER) {//sign就收工了
        return cycle;
    }
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);//獲取解析完成后 完成了init后的配置

 if (ngx_test_config) {//-t

        if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) {
            goto failed;
        }

    } else if (!ngx_is_init_cycle(old_cycle)) {

        /*
         * we do not create the pid file in the first ngx_init_cycle() call
         * because we need to write the demonized process pid
         */

        old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx,
                                                   ngx_core_module);
        if (ccf->pid.len != old_ccf->pid.len
            || ngx_strcmp(ccf->pid.data, old_ccf->pid.data) != 0)
        {
            /* new pid file name */

            if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) {
                goto failed;
            }

            ngx_delete_pidfile(old_cycle);
        }
    }

    if (ngx_test_lockfile(cycle->lock_file.data, log) != NGX_OK) {
        goto failed;
    }

    //創(chuàng)建在nginx.conf中涉及到文件路徑的文件夾
    if (ngx_create_paths(cycle, ccf->user) != NGX_OK) {
        goto failed;
    }

    if (ngx_log_open_default(cycle) != NGX_OK) {//設(shè)置默認(rèn)log文件
        goto failed;
    }


    /* open the new files */

    part = &cycle->open_files.part;
    file = part->elts;

    for (i = 0; /* void */ ; i++) {

        if (i >= part->nelts) {
            if (part->next == NULL) {
                break;
            }
            part = part->next;
            file = part->elts;
            i = 0;
        }

        if (file[i].name.len == 0) {
            continue;
        }

        file[i].fd = ngx_open_file(file[i].name.data,
                                   NGX_FILE_APPEND,
                                   NGX_FILE_CREATE_OR_OPEN,
                                   NGX_FILE_DEFAULT_ACCESS);

        ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0,
                       "log: %p %d \"%s\"",
                       &file[i], file[i].fd, file[i].name.data);

        if (file[i].fd == NGX_INVALID_FILE) {
            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                          ngx_open_file_n " \"%s\" failed",
                          file[i].name.data);
            goto failed;
        }

#if !(NGX_WIN32)
        if (fcntl(file[i].fd, F_SETFD, FD_CLOEXEC) == -1) {
            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                          "fcntl(FD_CLOEXEC) \"%s\" failed",
                          file[i].name.data);
            goto failed;
        }
#endif
    }
    cycle->log = &cycle->new_log;
    pool->log = &cycle->new_log;
 /*  走到這里的時候拦宣,所有的配置已經(jīng)解析完畢,如果配置"zone" proxy_cache_path fastcgi_cache_path等需要創(chuàng)建共享內(nèi)存信姓,則在下面依次創(chuàng)建對應(yīng)的共享內(nèi)存  */

 /* create shared memory */
    part = &cycle->shared_memory.part;
    shm_zone = part->elts;
    //ngx_cycle_t結(jié)構(gòu)體的shared_mem ory鏈表中將會開始初始化用于進程間通信的共享內(nèi)存鸵隧。
    for (i = 0; /* void */ ; i++) {
        if (i >= part->nelts) { //在熱啟動nginx的時候才會執(zhí)行下面的相關(guān)代碼,默認(rèn)i和part->nelts都等于0
            if (part->next == NULL) {
                break;
            }
            part = part->next;
            shm_zone = part->elts;
            i = 0;
        }

        if (shm_zone[i].shm.size == 0) {
            ngx_log_error(NGX_LOG_EMERG, log, 0,
                          "zero size shared memory zone \"%V\"",
                          &shm_zone[i].shm.name);
            goto failed;
        }

        shm_zone[i].shm.log = cycle->log;

        opart = &old_cycle->shared_memory.part;
        oshm_zone = opart->elts;

        for (n = 0; /* void */ ; n++) {

            if (n >= opart->nelts) {
                if (opart->next == NULL) {
                    break;
                }
                opart = opart->next;
                oshm_zone = opart->elts;
                n = 0;
            }

            if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) {
                continue;
            }

            if (ngx_strncmp(shm_zone[i].shm.name.data,
                            oshm_zone[n].shm.name.data,
                            shm_zone[i].shm.name.len) //
                != 0)
            {
                continue;
            }

            if (shm_zone[i].tag == oshm_zone[n].tag
                && shm_zone[i].shm.size == oshm_zone[n].shm.size
                && !shm_zone[i].noreuse)
            {
                shm_zone[i].shm.addr = oshm_zone[n].shm.addr;
#if (NGX_WIN32)
                shm_zone[i].shm.handle = oshm_zone[n].shm.handle;
#endif

                if (shm_zone[i].init(&shm_zone[i], oshm_zone[n].data)
                    != NGX_OK)
                {
                    goto failed;
                }

                goto shm_zone_found;
            }

            ngx_shm_free(&oshm_zone[n].shm);

            break;
        }

        if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) {
            goto failed;
        }

        if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) {
            goto failed;
        }

        if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) {
            goto failed;
        }

    shm_zone_found:

        continue;
    }

 /* handle the listening sockets */
/*
    listen所有在配置文件里面配置的端口
*/

 if (old_cycle->listening.nelts) {
        ls = old_cycle->listening.elts; //舊的listen,如熱啟動繼承過來的sock,
        for (i = 0; i < old_cycle->listening.nelts; i++) {
            ls[i].remain = 0;
        }

        nls = cycle->listening.elts; //從配置文件nginx.conf中l(wèi)isten的server ip和端口獲取到的信息
        for (n = 0; n < cycle->listening.nelts; n++) {

            for (i = 0; i < old_cycle->listening.nelts; i++) {
                if (ls[i].ignore) {
                    continue;
                }

                if (ls[i].remain) {
                    continue;
                }

                if (ngx_cmp_sockaddr(nls[n].sockaddr, nls[n].socklen,
                                     ls[i].sockaddr, ls[i].socklen, 1)
                    == NGX_OK)
                {
                    nls[n].fd = ls[i].fd;
                    nls[n].previous = &ls[i];
                    ls[i].remain = 1;

                    if (ls[i].backlog != nls[n].backlog) {
                        nls[n].listen = 1;
                    }

#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)

                    /*
                     * FreeBSD, except the most recent versions,
                     * could not remove accept filter
                     */
                    nls[n].deferred_accept = ls[i].deferred_accept;

                    if (ls[i].accept_filter && nls[n].accept_filter) {
                        if (ngx_strcmp(ls[i].accept_filter,
                                       nls[n].accept_filter)
                            != 0)
                        {
                            nls[n].delete_deferred = 1;
                            nls[n].add_deferred = 1;
                        }

                    } else if (ls[i].accept_filter) {
                        nls[n].delete_deferred = 1;

                    } else if (nls[n].accept_filter) {
                        nls[n].add_deferred = 1;
                    }
#endif

#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)

                    if (ls[i].deferred_accept && !nls[n].deferred_accept) {
                        nls[n].delete_deferred = 1;

                    } else if (ls[i].deferred_accept != nls[n].deferred_accept)
                    {
                        nls[n].add_deferred = 1;
                    }
#endif

#if (NGX_HAVE_REUSEPORT)
                    if (nls[n].reuseport && !ls[i].reuseport) {
                        nls[n].add_reuseport = 1;
                    }
#endif

                    break;
                }
            }

            if (nls[n].fd == (ngx_socket_t) -1) {
                nls[n].open = 1;
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
                if (nls[n].accept_filter) {
                    nls[n].add_deferred = 1;
                }
#endif
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
                if (nls[n].deferred_accept) {
                    nls[n].add_deferred = 1;
                }
#endif
            }
        }

    } else {
        ls = cycle->listening.elts;
        for (i = 0; i < cycle->listening.nelts; i++) {
            ls[i].open = 1;
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
            if (ls[i].accept_filter) {
                ls[i].add_deferred = 1;
            }
#endif
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
            if (ls[i].deferred_accept) {
                ls[i].add_deferred = 1;
            }
#endif
        }
    }

    if (ngx_open_listening_sockets(cycle) != NGX_OK) {// create bind listen
        goto failed;
    }
    if (!ngx_test_config) {
        ngx_configure_listening_sockets(cycle);//配置sock 重新listen
    }


    /* commit the new cycle configuration */

    if (!ngx_use_stderr) {
        (void) ngx_log_redirect_stderr(cycle);
    }

    for (i = 0; ngx_modules[i]; i++) {//調(diào)用module的init方法
        if (ngx_modules[i]->init_module) {
            if (ngx_modules[i]->init_module(cycle) != NGX_OK) {
                /* fatal */
                exit(1);
            }
        }
    }

/* close and delete stuff that lefts from an old cycle */

    /* free the unnecessary shared memory */

    opart = &old_cycle->shared_memory.part;
    oshm_zone = opart->elts;

    for (i = 0; /* void */ ; i++) {

        if (i >= opart->nelts) {
            if (opart->next == NULL) {
                goto old_shm_zone_done;
            }
            opart = opart->next;
            oshm_zone = opart->elts;
            i = 0;
        }

        part = &cycle->shared_memory.part;
        shm_zone = part->elts;

        for (n = 0; /* void */ ; n++) {

            if (n >= part->nelts) {
                if (part->next == NULL) {
                    break;
                }
                part = part->next;
                shm_zone = part->elts;
                n = 0;
            }

            if (oshm_zone[i].shm.name.len == shm_zone[n].shm.name.len
                && ngx_strncmp(oshm_zone[i].shm.name.data,
                               shm_zone[n].shm.name.data,
                               oshm_zone[i].shm.name.len)
                == 0)
            {
                goto live_shm_zone;
            }
        }

        ngx_shm_free(&oshm_zone[i].shm);

    live_shm_zone:

        continue;
    }

old_shm_zone_done:


    /* close the unnecessary listening sockets */

    ls = old_cycle->listening.elts;
    for (i = 0; i < old_cycle->listening.nelts; i++) {

        if (ls[i].remain || ls[i].fd == (ngx_socket_t) -1) {
            continue;
        }

        if (ngx_close_socket(ls[i].fd) == -1) {
            ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
                          ngx_close_socket_n " listening socket on %V failed",
                          &ls[i].addr_text);
        }

#if (NGX_HAVE_UNIX_DOMAIN)

        if (ls[i].sockaddr->sa_family == AF_UNIX) {
            u_char  *name;

            name = ls[i].addr_text.data + sizeof("unix:") - 1;

            ngx_log_error(NGX_LOG_WARN, cycle->log, 0,
                          "deleting socket %s", name);

            if (ngx_delete_file(name) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                              ngx_delete_file_n " %s failed", name);
            }
        }

#endif
    }


    /* close the unnecessary open files */

    part = &old_cycle->open_files.part;
    file = part->elts;

    for (i = 0; /* void */ ; i++) {

        if (i >= part->nelts) {
            if (part->next == NULL) {
                break;
            }
            part = part->next;
            file = part->elts;
            i = 0;
        }

        if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) {
            continue;
        }

        if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                          ngx_close_file_n " \"%s\" failed",
                          file[i].name.data);
        }
    }

 ngx_destroy_pool(conf.temp_pool);
//如果是第一次加載意推,則滿足ngx_is_init_cycle豆瘫。如果是reload熱啟動,則原來的nginx進程的ngx_process == NGX_PROCESS_MASTER    
    if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) { 

        /*
         * perl_destruct() frees environ, if it is not the same as it was at
         * perl_construct() time, therefore we save the previous cycle
         * environment before ngx_conf_parse() where it will be changed.
         */
        env = environ;
        environ = senv;

        ngx_destroy_pool(old_cycle->pool);
        cycle->old_cycle = NULL;

        environ = env;

        return cycle;
    }


    if (ngx_temp_pool == NULL) {
        ngx_temp_pool = ngx_create_pool(128, cycle->log);
        if (ngx_temp_pool == NULL) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
                          "could not create ngx_temp_pool");
            exit(1);
        }

        n = 10;
        ngx_old_cycles.elts = ngx_pcalloc(ngx_temp_pool,
                                          n * sizeof(ngx_cycle_t *));
        if (ngx_old_cycles.elts == NULL) {
            exit(1);
        }
        ngx_old_cycles.nelts = 0;
        ngx_old_cycles.size = sizeof(ngx_cycle_t *);
        ngx_old_cycles.nalloc = n;
        ngx_old_cycles.pool = ngx_temp_pool;

        ngx_cleaner_event.handler = ngx_clean_old_cycles;
        ngx_cleaner_event.log = cycle->log;
        ngx_cleaner_event.data = &dumb;
        dumb.fd = (ngx_socket_t) -1;
    }

    ngx_temp_pool->log = cycle->log;

    old = ngx_array_push(&ngx_old_cycles);
    if (old == NULL) {
        exit(1);
    }
    *old = old_cycle;

    if (!ngx_cleaner_event.timer_set) {
        ngx_add_timer(&ngx_cleaner_event, 30000, NGX_FUNC_LINE);
        ngx_cleaner_event.timer_set = 1;
    }

  return cycle;
//回到 main

    if (ngx_signal) { //加了-S參數(shù)
        return ngx_signal_process(cycle, ngx_signal);
    }

  ngx_os_status(cycle->log);

    ngx_cycle = cycle;

    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);

    if (ccf->master && ngx_process == NGX_PROCESS_SINGLE) { //在這里會把進程模式設(shè)置為MASTER模式
        ngx_process = NGX_PROCESS_MASTER;
    }
#if !(NGX_WIN32)

    if (ngx_init_signals(cycle->log) != NGX_OK) {
        return 1;
    }

    if (!ngx_inherited && ccf->daemon) {//啟動daemon
        if (ngx_daemon(cycle->log) != NGX_OK) {
            return 1;
        }

        ngx_daemonized = 1;
    }

    if (ngx_inherited) {
        ngx_daemonized = 1;
    }

#endif

 if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) {
        return 1;
    }

    if (ngx_log_redirect_stderr(cycle) != NGX_OK) {
        return 1;
    }

    if (log->file->fd != ngx_stderr) {
        //前面的log = ngx_log_init(ngx_prefix);
        if (ngx_close_file(log->file->fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          ngx_close_file_n " built-in log failed");
        }
    }

 ngx_use_stderr = 0;

//對于module會調(diào)用 init_process方法 然后進入事件循環(huán)
    if (ngx_process == NGX_PROCESS_SINGLE) { //
        ngx_single_process_cycle(cycle);
        
    } else { //一般都是走到這里菊值,master方式
        ngx_master_process_cycle(cycle);

  }

到這里啟動結(jié)束外驱。 后面來看下daemon master worker

只要的流程就是 初始化系統(tǒng)信息 創(chuàng)建core_module的conf 遞歸解析文件 偵聽端口 然后對共享內(nèi)存處理 確認(rèn)使用的process方式。
補一個ngx_cycle

struct ngx_cycle_s {
    void                  ****conf_ctx; //配置上下文數(shù)組()
    ngx_pool_t               *pool; //內(nèi)存池

    ngx_log_t                *log; //日志
    ngx_log_t                 new_log;

    ngx_uint_t                log_use_stderr;  /* unsigned  log_use_stderr:1; */

    ngx_connection_t        **files; //連接文件
    ngx_connection_t         *free_connections; //空閑鏈接
    ngx_uint_t                free_connection_n; //空閑鏈接個數(shù)

    ngx_queue_t               reusable_connections_queue; //reusable 鏈接隊列

    ngx_array_t               listening; //listen數(shù)組
    ngx_array_t               paths;// 路徑數(shù)組
    ngx_list_t                open_files;//打開文件列表
    ngx_list_t                shared_memory;//共享內(nèi)存鏈表

    ngx_uint_t                connection_n; //鏈接的個數(shù)
    ngx_uint_t                files_n; //打開文件的個數(shù)

    ngx_connection_t         *connections; //鏈接
    ngx_event_t              *read_events; //讀事件
    ngx_event_t              *write_events;//寫事件

    ngx_cycle_t              *old_cycle;//old

    ngx_str_t                 conf_file; //配置文件
    ngx_str_t                 conf_param;//配置文件參數(shù)
    ngx_str_t                 conf_prefix;//配置文件前綴
    ngx_str_t                 prefix;//前綴
    ngx_str_t                 lock_file;//鎖文件
    ngx_str_t                 hostname;//主機名
};
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末腻窒,一起剝皮案震驚了整個濱河市昵宇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌儿子,老刑警劉巖瓦哎,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異柔逼,居然都是意外死亡蒋譬,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門愉适,熙熙樓的掌柜王于貴愁眉苦臉地迎上來犯助,“玉大人,你說我怎么就攤上這事维咸〖谅颍” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵癌蓖,是天一觀的道長瞬哼。 經(jīng)常有香客問我,道長费坊,這世上最難降的妖魔是什么倒槐? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮附井,結(jié)果婚禮上讨越,老公的妹妹穿的比我還像新娘。我一直安慰自己永毅,他們只是感情好把跨,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著沼死,像睡著了一般着逐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天耸别,我揣著相機與錄音健芭,去河邊找鬼。 笑死秀姐,一個胖子當(dāng)著我的面吹牛慈迈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播省有,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼痒留,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蠢沿?” 一聲冷哼從身側(cè)響起伸头,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎舷蟀,沒想到半個月后恤磷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡雪侥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年碗殷,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片速缨。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡锌妻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出旬牲,到底是詐尸還是另有隱情仿粹,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布原茅,位于F島的核電站吭历,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏擂橘。R本人自食惡果不足惜晌区,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望通贞。 院中可真熱鬧朗若,春花似錦、人聲如沸昌罩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茎用。三九已至遣总,卻和暖如春睬罗,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背旭斥。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工容达, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人琉预。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓董饰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親圆米。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 本文系轉(zhuǎn)載》》》》》》》》》》》》》》》》 編者按:高可用架構(gòu)分享及傳播在架構(gòu)領(lǐng)域具有典型意義的文章啄栓,本文由陳科在...
    demop閱讀 8,042評論 0 7
  • 第一章 Nginx簡介 Nginx是什么 沒有聽過Nginx娄帖?那么一定聽過它的“同行”Apache吧!Ngi...
    JokerW閱讀 32,672評論 24 1,002
  • daemon: Linux Daemon(守護進程)是運行在后臺的一種特殊進程昙楚。它獨立于控制終端并且周期性地執(zhí)行某...
    燁哥閱讀 3,527評論 0 6
  • 上一篇《WEB請求處理一:瀏覽器請求發(fā)起處理》近速,我們講述了瀏覽器端請求發(fā)起過程,通過DNS域名解析服務(wù)器IP堪旧,并建...
    七寸知架構(gòu)閱讀 80,994評論 21 356
  • Chapter three 通過一年的努力削葱,紫秋考上了大學(xué)。在填志愿卻沒有填他所在的城市淳梦,選了一個北...
    暖暖檸閱讀 372評論 0 0