/* 以下只分析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;
}