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;