nginx启动流程分析

/* 以下只分析linux环境下的启动流程,非linux环境略过 */

int ngx_cdecl

main(int argc, char *const *argv)
{
    ngx_buf_t        *b;
    ngx_log_t        *log;
    ngx_uint_t        i;
    ngx_cycle_t      *cycle, init_cycle;
    ngx_conf_dump_t  *cd;
    ngx_core_conf_t  *ccf;

    /* debug相关环境初始化 */
    ngx_debug_init();

    /* 拷贝系统错误码及错误短语到ngx_sys_errlist全局变量中 */
    if (ngx_strerror_init() != NGX_OK) {
        return 1;
    }

    //获取命令行选项并赋值对应全局变量
    if (ngx_get_options(argc, argv) != NGX_OK) {
        return 1;
    }


    if (ngx_show_version) {
        ngx_show_version_info();


        if (!ngx_test_config) {
            return 0;
        }
    }


    /* TODO */ ngx_max_sockets = -1;

    //时间缓存初始化(获取当前时间,并各个时间缓存数组及变量)
    ngx_time_init();

    /* 如果指定使用pcre库,就在这里进行初始化 */
#if (NGX_PCRE)
    ngx_regex_init();
#endif

    /* 获取pid */
    ngx_pid = ngx_getpid();

   //错误日志初始化,包括设置默认错误日志级别,打开错误日志文件等
    log = ngx_log_init(ngx_prefix);
    if (log == NULL) {
        return 1;
    }

    //如果指定使用openssl库,就在这里进行SSL相关初始化,包括ssl库初始化,ssl相关全局变量初始化和赋值
    /* STUB */
#if (NGX_OPENSSL)
    ngx_ssl_init(log);
#endif


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

    /* nginx解析配置,加载模块,分配资源等核心任务在初次启动,

     * reload(或者平滑升级)时都需要执行,只是对于资源分配的处理上有一些不一样,

     * 因此nginx将它们都封装在ngx_init_cyle函数中,供启动或者reload时调用。

     * ngx_init_cycle函数通过入参来判断本次调用是初次启动还是reload,因此启动时需要先初始化init_cycle变量,

     * 设置好相关字段并作为参数传递给ngx_init_cycle,完成上述的核心任务。在nginx启动完成后,init_cycle就不再

     * 需要了。

     */

    ngx_memzero(&init_cycle, sizeof(ngx_cycle_t));
    init_cycle.log = log;
    ngx_cycle = &init_cycle;


    init_cycle.pool = ngx_create_pool(1024, log);//创建init_cycle的内存池
    if (init_cycle.pool == NULL) {
        return 1;
    }

    //把启动时的命令行参数和环境变量保存到nginx全局变量中,平滑升级时,作为启动参数传递给新的master进程
    if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) {
        return 1;
    }

    //对prefix,conf_prefix,conf_file,conf_param等与配置文件以及路径相关的变量进行赋值
    if (ngx_process_options(&init_cycle) != NGX_OK) {
        return 1;
    }

    //获取一些系统配置(内存页大小,cpu数量及基本信息,最大打开文件数等)
    if (ngx_os_init(log) != NGX_OK) {
        return 1;
    }


    /*
     * ngx_crc32_table_init() requires ngx_cacheline_size set in ngx_os_init()
     */

    /* crc32初始化 */
    if (ngx_crc32_table_init() != NGX_OK) {
        return 1;
    }

    /* 从环境变量"NGINX"中继承旧进程打开的socket。只有平滑升级时新的master启动时才会真正执行 */

    if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) {
        return 1;
    }

    //初始化模块索引和名称,计算当前模块总数和最大模块数
    if (ngx_preinit_modules() != NGX_OK) {
        return 1;
    }


    /* 初始化cycle,包括为各个成员变量申请内存,读取并解析配置文件,

     * 执行各模块上下文回调,打开各类资源(file,shm,socket)等 */

    cycle = ngx_init_cycle(&init_cycle);
    if (cycle == NULL) {
        if (ngx_test_config) {
            ngx_log_stderr(0, "configuration file %s test failed",
                           init_cycle.conf_file.data);
        }


        return 1;
    }

    

    /* 如果是测试配置文件,到这里说明测试已经通过,输出相关信息后直接退出,不再继续往下执行 */

    if (ngx_test_config) {
        if (!ngx_quiet_mode) {
            ngx_log_stderr(0, "configuration file %s test is successful",
                           cycle->conf_file.data);
        }


        if (ngx_dump_config) {
            cd = cycle->config_dump.elts;


            for (i = 0; i < cycle->config_dump.nelts; i++) {


                ngx_write_stdout("# configuration file ");
                (void) ngx_write_fd(ngx_stdout, cd[i].name.data,
                                    cd[i].name.len);
                ngx_write_stdout(":" NGX_LINEFEED);


                b = cd[i].buffer;


                (void) ngx_write_fd(ngx_stdout, b->pos, b->last - b->pos);
                ngx_write_stdout(NGX_LINEFEED);
            }
        }


        return 0;
    }


    /* ngx_signal不为空,表示这是一个信号发送进程(-s方式启动的),只要将信号发送给master进程,就可以退出了 */
    if (ngx_signal) {
        return ngx_signal_process(cycle, ngx_signal);
    }

    /* 将操作系统类型,版本等信息写入日志中 */
    ngx_os_status(cycle->log);

    /* 将cycle赋给全局变量ngx_cycle,供无法访问到cycle的场景使用 */
    ngx_cycle = cycle;

    /* 获取核心模块配置 */
    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);

   /* 如果配置中开启了master_process选项,就将本进程的角色设置为master */
    if (ccf->master && ngx_process == NGX_PROCESS_SINGLE) {
        ngx_process = NGX_PROCESS_MASTER;
    }


#if !(NGX_WIN32)


    /* 注册master感兴趣的信号及信号处理函数 */
    if (ngx_init_signals(cycle->log) != NGX_OK) {
        return 1;
    }


    /* 如果是初次启动的master进程,并且开启了daemon配置,就以守护进程方式运行 */
    if (!ngx_inherited && ccf->daemon) {
        if (ngx_daemon(cycle->log) != NGX_OK) {
            return 1;
        }


        ngx_daemonized = 1;
    }

    /* ngx_inherited等于1,说明该进程是平滑升级启动的新master进程,所以一定是以守护进程方式运行的,

     * 因为新的master是由旧的master通过fork创建出来的 */

    if (ngx_inherited) {
        ngx_daemonized = 1;
    }


#endif

    /* 初次启动,创建pid文件,并写入当前进程的pid */
    if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) {
        return 1;
    }


    /* 标准错误重定向到打开的log文件描述符 */
    if (ngx_log_redirect_stderr(cycle) != NGX_OK) {
        return 1;
    }


    if (log->file->fd != ngx_stderr) {
        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 */

    ngx_use_stderr = 0;


    if (ngx_process == NGX_PROCESS_SINGLE) {
        /* 以单进程方式运行 */
        ngx_single_process_cycle(cycle);


    } else {
        /* 以master-worker方式运行 */
        ngx_master_process_cycle(cycle);
    }


    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值