http://blog.chinaunix.net/uid-27767798-id-3757684.html
http://blog.csdn.net/brainkick/article/details/6842216
http://blog.sunheqiubai.com/?cat=5&paged=2
http://blog.csdn.net/chosen0ne/article/details/7730292
在nginx中每个块都会对应一个相应类型core module,比如整个配置文件的main块对应的就是ngx_core_module,events块对应的是ngx_event_core_module,而http块对应就是ngx_http_core_module。这些具体类型的core module主要是处理相应块内的指令,并保存一些重要的配置信息。
Events Http
/ \
Server Server
/ \ \
Location Location Location
这棵树中,每个节点对应一个配置块,配置文件的解析就是对这棵树的深度优先遍历,并对每个节点调用ngx_conf_parse函数。其中的Http节点对应的就是ngx_http_module模块,是由它驱动后面的server块和location块的解析
//ngx_module_s只是一个通用的模块数据结构,对于具体的模块类型是它的ctx字段 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_CORE_MODULE, NGX_CONF_MODULE, NGX_HTTP_MODULE, NGX_EVENT_MODULE, NGX_MAIL_MODULE ngx_int_t (*init_master)(ngx_log_t *log); ngx_int_t (*init_module)(ngx_cycle_t *cycle); ngx_int_t (*init_process)(ngx_cycle_t *cycle); ngx_int_t (*init_thread)(ngx_cycle_t *cycle); void (*exit_thread)(ngx_cycle_t *cycle); void (*exit_process)(ngx_cycle_t *cycle); void (*exit_master)(ngx_cycle_t *cycle); 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; };
获得模块的配置:
ngx_get_conf(cycle->conf_ctx, ngx_events_module);
是核心模块且其字段create_conf非空的模块配置的创建在ngx_init_cycle()中:
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; } }
模块的配置结构创建存储都是在配置解析过程中完成的
NGX_EVENT_MODULE类型模块配置结构的创建在解析配置文件的时候
(gdb) bt
#0 ngx_event_core_create_conf (cycle=0x6f6780) at src/event/ngx_event.c:1162
#1 0x000000000042b17b in ngx_events_block (cf=0x7fffffffe290, cmd=0x6d4b00, conf=0x6f7648) at src/event/ngx_event.c:920
#2 0x000000000041de01 in ngx_conf_handler (cf=0x7fffffffe290, last=1) at src/core/ngx_conf_file.c:391
#3 0x000000000041d9ad in ngx_conf_parse (cf=0x7fffffffe290, filename=0x6f6900) at src/core/ngx_conf_file.c:247
#4 0x000000000041a560 in ngx_init_cycle (old_cycle=0x7fffffffe3d0) at src/core/ngx_cycle.c:264
#5 0x0000000000403324 in main (argc=1, argv=0x7fffffffe6b8) at src/core/nginx.c:333
(gdb)
不过, 在ngx_events_module中实现的核心模块却没有实现此函数, ngx_event_init_conf函数也只是简单进行正确性判断.
这是因为ngx_events_module模块并不会解析配置项的参数, 只是在出现events配置项后会调用各事件模块去解析events{...}块内的配置项, 所以也就不需要什么存储结构体了.
- 配置解析的时机是在 fork 调用之前,换句话说所有因为配置解析而产生的内存(包括自定义模块的内存)都是在 fork 之前分配,但是由于 linux 的写时拷贝机制,所以并不会在物理内存中存在多份拷贝;
=========================
ngx_init_cycle()中的几件事件:
父进程中
- 核心模块的配置结构的显示创建 module->create_conf(cycle)
- 非核心模块的配置结构的创建和初始化 ngx_conf_parse()
- 核心模块的配置结构的初始化 module->init_conf()
- 所有模块的模块初始化 ngx_modules[i]->init_module()
子进程中
所有模块的进程初始化: ngx_modules[i]->init_process(cycle)
见如下调用栈
(gdb) bt
#0 ngx_event_process_init (cycle=0x6f6780) at src/event/ngx_event.c:585
#1 0x00000000004379f6 in ngx_worker_process_init (cycle=0x6f6780, worker=0) at src/os/unix/ngx_process_cycle.c:981
#2 0x0000000000437126 in ngx_worker_process_cycle (cycle=0x6f6780, data=0x0) at src/os/unix/ngx_process_cycle.c:746
#3 0x0000000000433ae6 in ngx_spawn_process (cycle=0x6f6780, proc=0x4370f0 <ngx_worker_process_cycle>, data=0x0,
name=0x4b89cb "worker process", respawn=-3) at src/os/unix/ngx_process.c:198
#4 0x0000000000436083 in ngx_start_worker_processes (cycle=0x6f6780, n=3, type=-3) at src/os/unix/ngx_process_cycle.c:368
#5 0x00000000004356c1 in ngx_master_process_cycle (cycle=0x6f6780) at src/os/unix/ngx_process_cycle.c:140
#6 0x0000000000403573 in main (argc=1, argv=0x7fffffffe6b8) at src/core/nginx.c:407
ngx_event_process_init ()中module->actions.init(cycle, ngx_timer_resolution),即对ngx_epoll_init()的调用
Nginx启动的时候会先进行core类型模块的处理。在Nginx的每一部分都会有一个core类型的模块与之对应,在解析配置文件的时候,这些core类型的模块便是他们所代表部分的入口。
例如event部分,ngx_events_module模块就是一个NGX_CORE_MODULE的模块,因而我们可以看到event部分的初始化其实是从ngx_events_module模块的命令events的set回调函数开始的。
在每一部分都有一个比较重要的核心模块,例如event部分有NGX_EVENT_MODULE类型的ngx_event_core_module模块,其虽然只是一个event类型的模块,但是其却处理了event部分的大多数命令,
而且它的配置结构也会保存很多十分重要的信息,例如ngx_event_core_module的配置结构ngx_event_conf_t就保存了event是否使用互斥信号,具体使用哪一个时间模块的等信息。
其实要分析nginx不同部分就应该从这两种模块开始。
分析http部分吧,先找到core类型的模块,它是ngx_http_module模块
我们知道每种类型的模块的配置结构并不是保存在模块内部的,我们可以看到全局cycle变量有一个域是ctx,它用来保存“所有”模块的配置结构上下文,这里用引号是有道理的。其实ctx只是保存了每一部分core类型的模块的配置结构,
然后再用core类型模块的配置结构来保存其所在部分的其余具体模块的配置结构,然后其余具体模块想要获取其的配置,就得先找到代表它的core类型的模块,进而才能找到其的配置结构。也就是说模块的配置结构的保存其实是按照层次来进行的