1) 初始化错误提示列表,以errno为下标,元素就是对应的错误提示信息。 1: if (ngx_strerror_init() != NGX_OK) { 2: return 1; 3: } 2)获取命令行参数,保存在全局变量中,可以设置的命令行参数如下表所示: 1: if (ngx_get_options(argc, argv) != NGX_OK) { 2: return 1; 3: } 3)时间、正则表达式和log的初始化。 1: ngx_time_init(); 2: 3: (NGX_PCRE) 4: ngx_regex_init(); 5: if 6: 7: ngx_pid = ngx_getpid(); 8: 9: log = ngx_log_init(ngx_prefix); 10: if (log == NULL) { 11: return 1; 12: } 4)初始化cycle结构,并创建内存块大小为1024的内存池,内存池创讨论过了,nginx框架就是围绕着ngx_cycle_t结构体来控制运行的 1: ngx_memzero(&init_cycle, sizeof(ngx_cycle_t)); 2: init_cycle.log = log; 3: ngx_cycle = &init_cycle; 4: 5: init_cycle.pool = ngx_create_pool(1024, log); 6: if (init_cycle.pool == NULL) { 7: return 1; 8: } 5) 将命令行参数保存到ngx_os_argv、ngx_argc以及ngx_argv这几个全局的变量中。这算是一个备份存储,方便以后master进程做热代码替换之用。 1: if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) { 2: return 1; 3: } 6)用命令行参数得来的全局变量初始化cycle的conf_prefix(配置文件所在路径的前缀)、prefix(nginx可执行文件所在路径)、conf_file(配置文件名)和conf_param(通过命令行-g选项指定的全局配置信息)。 1: if (ngx_process_options(&init_cycle) != NGX_OK) { 2: return 1; 3: } 7) 根据操作系统确定一些参数,信息会被保存到一些全局变量中,如页大小ngx_pagesize, CPU cacheline 1: if (ngx_os_init(log) != NGX_OK) { 2: return 1; 3: } 8) 初始化一个做循环冗余校验的表,由此可以看出后续的循环冗余校验将采用高效的查表法 1: if (ngx_crc32_table_init() != NGX_OK) { 2: return 1; 3: } 9)通过环境变量NGINX完成socket的继承,继承来的socket将会放到init_cycle的listening数组中。同时可以读取master进程传递的平滑升级信息等等 1: if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) { 2: return 1; 3: } 10)初始化所有模块的index信息,即对所有模块进行编号,ngx_modules数却是在自动编译的时候生成的,位于objs/ngx_modules.c文件中 1: ngx_max_module = 0; 2: for (i = 0; ngx_modules[i]; i++) { 3: ngx_modules[i]->index = ngx_max_module++; 4: } 11) 用上面收集的init_cycle信息初始化ngx_cycle,这行代码是nginx启动过程中最重要的一个步骤,在第3节将详细展开。 1: cycle = ngx_init_cycle(&init_cycle); 2: if (cycle == NULL) { 3: if (ngx_test_config) { 4: ngx_log_stderr(0, "configuration file %s test failed", 5: init_cycle.conf_file.data); 6: } 7: 8: return 1; 9: } 12)ccf 为ngx_core_conf_t 将在第2节给出详细定义,这个地方需要解释下,ccf->master是从配置文件中解析master_process配置项所得的值,初始化为NGX_CONF_UNSET(-1),在配置项中,如果flag类型的配置项master_process被设置为on,则其值为1,如果为off,则其值为0,ngx_process为全局变量,用于记录要采用的工作模式,未被初始化,因此初始值是0(uint型全局变量会被系统默认初始化为0),相关宏定义如下: #define NGX_PROCESS_SINGLE 0 #define NGX_PROCESS_MASTER 1 #define NGX_PROCESS_SIGNALLER 2 #define NGX_PROCESS_WORKER 3 #define NGX_PROCESS_HELPER 4 因此,下面的if判断语句的含义就是:用来处理一种特殊情况,即如果在配置项中未设置master_process配置项或者是设置为打开,ngx_process未被设置,采用默认值0,这个时候要采用master工作模式。因为master_process优先级高,且nginx默认采用master模式如果在配置项中设置master_process为off,那么if依据不会执行。最终nginx工作模式取决于ngx_proces的初值0,即采用单进程模式。 1: ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); 2: 3: if (ccf->master && ngx_process == NGX_PROCESS_SINGLE) { 4: ngx_process = NGX_PROCESS_MASTER; 5: } 13)初始化信号;主要完成信号处理程序的注册 1: if (ngx_init_signals(cycle->log) != NGX_OK) { 2: return 1; 3: } 14)若无继承sockets,且设置了守护进程表示,则创建守护进程 1: if (!ngx_inherited && ccf->daemon) { 2: if (ngx_daemon(cycle->log) != NGX_OK) { 3: return 1; 4: } 5: 6: ngx_daemonized = 1; 7: } 8: 9: if (ngx_inherited) { 10: ngx_daemonized = 1; 11: } 15) 创建进程记录文件;(非NGX_PROCESS_MASTER=1进程,不创建该文件) 1: if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) { 2: return 1; 3: } 16) 进入进程主循环,根据ngx_process确定启动单进程模式还是多进程模式。 1: if (ngx_process == NGX_PROCESS_SINGLE) { 2: ngx_single_process_cycle(cycle); 3: 4: } else { 5: ngx_master_process_cycle(cycle); 6: } 2.相关结构体 2.1. ngx_module_t nginx中所有模块的类型都是ngx_module_t类型的,定义了模块的一些属性。nginx是完全模块化的,所有的组件都是模块,从而实现了nginx的高度松耦合。同时,我们在进行nginx模块开发时,也离不开这个数据结构。在上面初始化过程中的第10步就是初始化这个结构。 1: struct ngx_module_s { 2: /** 3: * 在具体类型模块(http、event等)的全局配置结构数组的下标。以http module模块为例, 4: * nginx把所有的http module的config信息存放在ngx_http_conf_ctx_t类型的变量中, 5: * 这个变量只有3个属性,分别是所有http module的main、srv、loc的config信息的数组。 6: * 如果该模块是http module,则ctx_index是该模块的config信息(main、srv、loc) 7: * 在ngx_http_conf_ctx_t中的下标。 8: */ 9: ngx_uint_t ctx_index; 10: 11: /** 12: * nginx把所有模块(ngx_module_t)存放到ngx_modules数组中,这个数组在nginx源码路 13: * 径的objs/ngx_modules.c中,是在运行configure脚本后生成的。index属性就是该模块 14: * 在ngx_modules数组中的下标。同时nginx把所有的core module的配置结构存放到ngx_cycle的 15: * conf_ctx数组中,index也是该模块的配置结构在ngx_cycle->conf_ctx数组中的下标。 16: */ 17: ngx_uint_t index; 18: 19: …… 20: 21: /** 22: * 模块的上下文属性,同一类型的模块的属性是相同的,比如core module的ctx是ngx_core_module_t类型。 23: * 而http module的ctx是ngx_http_moduel_t类型,event module的ctx是ngx_event_module_t类型等等。 24: * 相应类型的模块由分开处理的,比如所有的http module由ngx_http_module解析处理,而所有的event module 25: * 由ngx_events_module解析处理。 26: */ 27: void *ctx; 28: 29: /** 30: * 该模块支持的指令的数组,最后以一个空指令结尾。ngx_commond_t的分析见下文。 31: */ 32: ngx_command_t *commands; 33: 34: /** 35: * 模块的类型,nginx所有的模块类型: 36: * NGX_CORE_MODULE 37: * NGX_CONF_MODULE 38: * NGX_HTTP_MODULE 39: * NGX_EVENT_MODULE 40: * NGX_MAIL_MODULE 41: * 这些不同的类型也指定了不同的ctx。 42: */ 43: ngx_uint_t type; 44: 45: /* 接下来都是一些回调函数,在nginx初始化过程的特定时间点调用 */ 46: ngx_int_t (*init_master)(ngx_log_t *log); 47: 48: /* 初始化完所有模块后调用,在ngx_int_cycle函数(ngx_cycle.c)中 */ 49: ngx_int_t (*init_module)(ngx_cycle_t *cycle); 50: 51: /* 初始化完worker进程后调用,在ngx_worker_process_init函数(ngx_process_cycle.c)中 */ 52: ngx_int_t (*init_process)(ngx_cycle_t *cycle); 53: ngx_int_t (*init_thread)(ngx_cycle_t *cycle); 54: void (*exit_thread)(ngx_cycle_t *cycle); 55: void (*exit_process)(ngx_cycle_t *cycle); 56: 57: void (*exit_master)(ngx_cycle_t *cycle); 58: …… 59: }; 2) 创建内存池,并从内存池中创建ngx_cycle_t结构,然后给cycle日志和old_cycle赋值 1: log = old_cycle->log; 2: 3: pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log); 4: if (pool == NULL) { 5: return NULL; 6: } 7: pool->log = log; 8: 9: cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t)); 10: if (cycle == NULL) { 11: ngx_destroy_pool(pool); 12: return NULL; 13: } 14: 15: cycle->pool = pool; 16: cycle->log = log; 17: cycle->old_cycle = old_cycle;