Nginx
中定義了許多基本數(shù)據(jù)結(jié)構(gòu),如雙向鏈表ngx_queue_t
、動(dòng)態(tài)數(shù)組ngx_array_t
等等爽锥。也定義了與功能息息相關(guān)的復(fù)雜的數(shù)據(jù)結(jié)構(gòu),其中最核心的有:ngx_cycle_t ngx_module_t ngx_command_t
等授舟。這里我們著重分析ngx_cycle_t
結(jié)構(gòu)體成員——void ****conf_ctx
在 ngx_init_cycle函數(shù)執(zhí)行完成后,其所指向的內(nèi)存的一系列變化贸辈。
conf_ctx
是一個(gè)指向配置項(xiàng)結(jié)構(gòu)體的指針释树。之所以有4個(gè)****,是因?yàn)樵撝羔樦赶蛞粋€(gè)存儲(chǔ)著指針的數(shù)組,這個(gè)數(shù)組中的指針元素又有可能指向另一個(gè)存放指針的數(shù)組擎淤。具體結(jié)構(gòu)圖將在后文中給出奢啥。
1. conf_ctx指向指針數(shù)組
分配一塊連續(xù)內(nèi)存(數(shù)組),用于保存ngx_max_module
個(gè)指針元素,每個(gè)指針元素按位置對(duì)應(yīng)一個(gè)模塊數(shù)組中的模塊嘴拢,指向?qū)?yīng)于該模塊的配置項(xiàng)結(jié)構(gòu)體或者配置項(xiàng)結(jié)構(gòu)體指針數(shù)組桩盲。ngx_max_module
為總的模塊個(gè)數(shù)。cycle->conf_ctx
保存數(shù)組首地址,代碼如下:
cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));
//ngx_init_cycle()函數(shù)
之后的內(nèi)存結(jié)構(gòu)如圖所示席吴,本人通過(guò)gdb調(diào)試取得赌结,本次conf_ctx地址為:0x101011a28
2.回調(diào)核心模塊create_conf函數(shù)
接下來(lái),遍歷模塊數(shù)組cycle->modules
,找到核心模塊孝冒,回調(diào)其create_conf
函數(shù)柬姚,創(chuàng)建配置項(xiàng)結(jié)構(gòu)體,將相應(yīng)地址存放于圖1中的數(shù)組內(nèi)庄涡。
摘自ngx_init_cycle函數(shù)
for (i = 0; cycle->modules[i]; i++) {
if (cycle->modules[i]->type != NGX_CORE_MODULE) {
continue;
}
module = cycle->modules[i]->ctx;
if (module->create_conf) {
rv = module->create_conf(cycle);
if (rv == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
cycle->conf_ctx[cycle->modules[i]->index] = rv;
}
}
cycle->conf_ctx[cycle->modules[i]->index] = rv;
語(yǔ)句的執(zhí)行結(jié)果量承,如圖2所示:
圖2與圖1對(duì)比可見(jiàn),只有少部分?jǐn)?shù)組元素保存了指向配置項(xiàng)結(jié)構(gòu)體的有效地址穴店。比如cycle->conf_ctx[0]
保存了指向ngx_core_module
模塊的配置項(xiàng)結(jié)構(gòu)體指針撕捍,cycle->conf_ctx[4]理應(yīng)保存指向ngx_event_module模塊結(jié)構(gòu)體指針數(shù)組的指針,但現(xiàn)在是0x0
.
那么這些位置的數(shù)組元素是在何時(shí)保存有效指針的呢? 答案是:解析配置文件的時(shí)候泣洞。
3. 解析配置文件忧风,處理配置項(xiàng)及其它
除了解析配置文件,處理配置項(xiàng)球凰,還有可能創(chuàng)建下一級(jí)的指針數(shù)組阀蒂。
代碼如下所示,:
//`摘自ngx_init_cycle函數(shù)`
if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {
environ = senv;
ngx_destroy_cycle_pools(&conf);
return NULL;
}
conf
實(shí)參中保存了conf_ctx
和cycle
變量的副本。進(jìn)入·ngx_conf_parse·函數(shù)內(nèi)部弟蚀,略過(guò)諸多細(xì)節(jié)蚤霞,看關(guān)鍵性代碼:
回調(diào)模塊自身注冊(cè)的配置處理函數(shù),
rv = (*cf->handler)(cf, NULL, cf->handler_conf);
//cf 即 conf實(shí)參
或者义钉,調(diào)用通用的配置處理函數(shù):
rc = ngx_conf_handler(cf, rc);
假設(shè)調(diào)用ngx_conf_handler
函數(shù)昧绣,進(jìn)入該函數(shù)內(nèi)部:
if (cmd->type & NGX_DIRECT_CONF) {
conf = ((void **) cf->ctx)[cf->cycle->modules[i]->index];
} else if (cmd->type & NGX_MAIN_CONF) {
conf = &(((void **) cf->ctx)[cf->cycle->modules[i]->index]);
} else if (cf->ctx) {
confp = *(void **) ((char *) cf->ctx + cmd->conf);
if (confp) {
conf = confp[cf->cycle->modules[i]->ctx_index];
}
}
解析一下上面的代碼。
conf
是該函數(shù)定義的ngx_conf_t
類(lèi)型的局部變量捶闸,cmd
變量的類(lèi)型是ngx_command_t
夜畴。
我們知道拖刃,定義一個(gè)模塊,首先就是實(shí)現(xiàn)ngx_module_t
結(jié)構(gòu)體贪绘,該結(jié)構(gòu)體內(nèi)就有一個(gè)ngx_command_t
數(shù)組成員兑牡,該成員決定了該模塊對(duì)那些配置項(xiàng)感興趣,以及如何處理自己感興趣的配置項(xiàng)税灌,換言之——定制功能均函。
舉例1——ngx_events_module
模塊,其ngx_command_t
數(shù)組成員如下:
static ngx_command_t ngx_events_commands[] = {
{ ngx_string("events"), // 配置項(xiàng)名稱(chēng)
NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, //配置項(xiàng)類(lèi)型
ngx_events_block, //處理配置項(xiàng)的函數(shù)
0,
0,
NULL },
ngx_null_command
};
可以看到菱涤,ngx_events_module
模塊只對(duì)event{...}
塊配置項(xiàng)感興趣苞也,并且使用ngx_events_block
函數(shù)處理該配置項(xiàng)。
舉例2——ngx_core_module
模塊粘秆,其ngx_command_t
數(shù)組成員如下:
static ngx_command_t ngx_core_commands[] = {
......
......
{ ngx_string("worker_processes"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
ngx_set_worker_processes,
0,
0,
NULL },
......
......
}
在cmd->type
的取值中: NGX_MAIN_CONF
和 NGX_DIRECT_CONF
功能很難用語(yǔ)言清晰總結(jié)如迟,我們直接看其功能:
當(dāng)
cmd->type
值的組成中有NGX_DIRECT_CONF
參與時(shí)(比如ngx_core_module
模塊),局部變量conf
取值如下:
conf = ((void **) cf->ctx)[cf->cycle->modules[i]->index];
cf->ctx 也就是前文中conf_ctx的副本攻走,cf->cycle->modules[i]->index是模塊在模塊數(shù)組中的索引元潘,前文中已經(jīng)描述了模塊數(shù)組與conf_ctx所指向數(shù)組的一一對(duì)應(yīng)關(guān)系箫攀。
由于void*不能被解引用饵较,所以這里轉(zhuǎn)換為void **迫筑,假設(shè)是cf->cycle->modules[i]得到是ngx_core_module模塊,那么有index==0巩趁,因此等價(jià)于:
conf = conf_ctx[0];
//即 0x0000000101012580,如圖2所示
-
當(dāng)cmd->type值的組成中無(wú)
NGX_DIRECT_CONF
參與痒玩,有NGX_MAIN_CONF
參與時(shí)(如ngx_events_module
模塊),局部變量conf取值如下:
conf =& (((void **) cf->ctx)[cf->cycle->modules[i]->index]);
對(duì)于ngx_events_module
模塊议慰,已知cf->cycle->modules[i]->index == 4
(如圖2)蠢古,那么對(duì)conf
就是對(duì)conf_ctx[4]
取地址后的值。
所以有如下示意圖:
圖3:指向指針數(shù)組某元素的指針conf.png
接下來(lái)將通過(guò)ngx_command_t
的函數(shù)指針set
别凹,回調(diào)單個(gè)配置項(xiàng)處理函數(shù)草讶。如:
ngx_core_module
的ngx_set_worker_processes
函數(shù)處理worker_processes
配置項(xiàng)
ngx_events_module
的ngx_events_block
函數(shù)處理events{...}
塊配置項(xiàng)。
并且將conf
指針傳入被回調(diào)函數(shù)內(nèi)炉菲。
對(duì)于ngx_core_module
堕战,觀(guān)察ngx_core_commands[]
內(nèi)的一系列配置項(xiàng)處理函數(shù),不難得出拍霜,conf
直接指向其配置項(xiàng)結(jié)構(gòu)體嘱丢,因此有圖4:
對(duì)于ngx_events_module
模塊,分析其ngx_events_block
函數(shù):
ctx = ngx_pcalloc(cf->pool, sizeof(void *));
...
*ctx = ngx_pcalloc(cf->pool, ngx_event_max_module * sizeof(void *));
...
*(void **) conf = ctx;
第一句:為指針ctx
分配了內(nèi)存空間
第二句:分配一個(gè)ngx_event_max_module
大小的指針數(shù)組祠饺,ngx_event_max_module
是events
子模塊的數(shù)目越驻;令ctx
指向該數(shù)組。
第三句:將ctx
的值賦給conf指向的數(shù)組元素(如圖3),也就是令該數(shù)組元素內(nèi)保存的指針指向第二句中分配的指針數(shù)組缀旁。
因此有如圖5:
接下來(lái)记劈,執(zhí)行過(guò)程類(lèi)似于本文中的2、3步并巍,該函數(shù)內(nèi)部又將調(diào)用create_conf
創(chuàng)建事件子模塊配置項(xiàng)結(jié)構(gòu)體目木,正如開(kāi)始時(shí)創(chuàng)建核心模塊配置項(xiàng)結(jié)構(gòu)體那般,并把地址保存于圖5中下一個(gè)指針數(shù)組中的相應(yīng)位置懊渡,然后調(diào)用ngx_conf_parse
函數(shù)解析配置文件刽射,處理配置項(xiàng)。
結(jié)果如圖6所示:
在執(zhí)行守護(hù)程序之前距贷,在gdb中查看內(nèi)存:x/100xg ngx_cycle->conf_ctx
,打印信息如下柄冲,可見(jiàn)仍有許多單元沒(méi)有被存入有效地址吻谋。
0x101011a28: 0x0000000101012580 0x0000000000000000
0x101011a38: 0x0000000000000000 0x0000000101012678
0x101011a48: 0x00000001010132f0 0x0000000000000000
0x101011a58: 0x0000000000000000 0x0000000101013430
0x101011a68: 0x0000000000000000 0x0000000000000000
0x101011a78: 0x0000000000000000 0x0000000000000000
0x101011a88: 0x0000000000000000 0x0000000000000000
0x101011a98: 0x0000000000000000 0x0000000000000000
0x101011aa8: 0x0000000000000000 0x0000000000000000
0x101011ab8: 0x0000000000000000 0x0000000000000000
0x101011ac8: 0x0000000000000000 0x0000000000000000
0x101011ad8: 0x0000000000000000 0x0000000000000000
0x101011ae8: 0x0000000000000000 0x0000000000000000
未完待續(xù)忠蝗。。