好記性不如爛筆頭!剛開始看完一遍nginx的原始碼,由于原始碼工程量比較大,看完之后理解了,過一段時間再回過頭來看又有點遺忘,所以決定做一下記錄,以便后續翻閱,如有漏錯,歡迎指正,
ngx_cycle_s結構體可以說是Nginx中最為重要的結構體,它貫穿著整個行程代碼,本節我就該結構中的 void ****conf_ctx 四級指標進行深入學習,
Nginx的所有配置結構體全部放在conf_ctx這個四維指標中,下來我們梳理一下原始碼,主要對HTTP模塊所對應的四維指標進行詳細分析,其它模塊同理,再次就不再做贅述,下來先看一下原始碼中的ngx_init_cycle函式,主要代碼如下:
ngx_cycle_t* ngx_init_cycle(ngx_cycle_t *old_cycle)
{
……
// conf_ctx指標 指向ngx_max_module個 (void *) 指標指向每個模塊
cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));
if (cycle->conf_ctx == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
……
// conf_ctx指標中 modules 二級指標指向 ngx_modules 全域變數
if (ngx_cycle_modules(cycle) != NGX_OK) {
ngx_destroy_pool(pool);
return NULL;
}
// 只有core模塊才有create_conf, init_conf結構
for (i = 0; cycle->modules[i]; i++) {
if (cycle->modules[i]->type != NGX_CORE_MODULE) {
continue;
}
// 指向各CORE模塊的 module context
// 對應http模塊來說指向&ngx_http_module_ctx
module = cycle->modules[i]->ctx;
if (module->create_conf) {
rv = module->create_conf(cycle);
if (rv == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
// 每個模塊create_conf回傳 void * 對應的 conf_ctx[i] 中
cycle->conf_ctx[cycle->modules[i]->index] = rv;
}
}
……
// conf的ctx指向cycle中的四維指標conf_ctx
conf.ctx = cycle->conf_ctx;
conf.cycle = cycle;
conf.pool = pool;
conf.log = log;
conf.module_type = NGX_CORE_MODULE;
conf.cmd_type = NGX_MAIN_CONF;
……
// 決議組態檔
if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {
environ = senv;
ngx_destroy_cycle_pools(&conf);
return NULL;
}
……
}
上述代碼實作的conf_ctx這個四維指標中的其中兩維,
1、一維是申請并指向所有模塊(ngx_max_module個 (void *) 指標)的配置,而并非所有主模塊的配置,
2、二維指向對應主模塊的create_conf函式(只有ngx_core_module模塊該函式指標不為NULL)所回傳的記憶體,對應http模塊則對應的create_conf為NULL,因此它的二維目前指的為NULL,
結合上述代碼的后半段及以下代碼分析,ngx_conf_handler函式是ngx_conf_parse決議組態檔時呼叫的,主要代碼如下:
static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
{
……
if (cmd->type & NGX_DIRECT_CONF) // 主模塊 ngx_core_commands 中命令
{
conf = ((void **) cf->ctx)[cf->cycle->modules[i]->index];
}
else if (cmd->type & NGX_MAIN_CONF) // 子模塊event、http、mail 中命令
{
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];
}
}
// 呼叫對應命令的set回呼函式
rv = cmd->set(cf, cmd, conf);
……
}
上述代碼中cf->ctx指向cycle中的四維指標conf_ctx;上述我們已將思維指標的其中二維已經分析即:所有模塊的一維指標已初始化,ngx_core_module模塊的二維指標已初始化(其他event、http、mail 對應的create_conf函式指標都為NULL),
下來分析ngx_conf_handler函式,因為 http命令字的type為 :NGX_MAIN_CONF,因此當遇到http{}關鍵字時,對應會執行:conf =&(((void **) cf->ctx)[cf->cycle->modules[i]->index]),我們下來分析一下該陳述句,
當命令型別為 NGX_DIRECT_CONF 時,說明該命令為 ngx_core_module 模塊命令,因為ngx_core_module 模塊有 create_conf 函式,此時:conf_ctx中的一維指標中的 void* 已經通過core模塊的create_conf函式申請了空間,所以只需將conf指標指向申請的空間就行,對應執行:conf = ((void **) cf->ctx)[cf->cycle->modules[i]->index],
當命令型別為 NGX_MAIN_CONF時,對應所以的子模塊(event、http、mail)都沒有實作create_conf函式,因此需取出void*的地址來通過各自模塊的ngx_xxx_block函式為其申請空間,對應執行:conf = &((void **) cf->ctx)[cf->cycle->modules[i]->index],
然后將conf指標作為cmd->set()函式的回呼函式的引數并執行,對于http命令來說將呼叫nginx_http_block函式,主要代碼如下:
static char * ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
……
if (*(ngx_http_conf_ctx_t **) conf) {
return "is duplicate";
}
// 申請 ngx_http_conf_ctx_t 結構的記憶體
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}
// *conf 實質等于 陣列申請的 void*
*(ngx_http_conf_ctx_t **) conf = ctx;
// 以下3個ngx_pcalloc申請 ngx_http_conf_ctx_t 結構中的三個二維指標記憶體
ctx->main_conf = ngx_pcalloc(cf->pool,
sizeof(void *) * ngx_http_max_module);
if (ctx->main_conf == NULL) {
return NGX_CONF_ERROR;
}
ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
if (ctx->srv_conf == NULL) {
return NGX_CONF_ERROR;
}
ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
if (ctx->loc_conf == NULL) {
return NGX_CONF_ERROR;
}
// 呼叫對應http模塊的create_main_conf、create_srv_conf、create_loc_conf函式
for (m = 0; cf->cycle->modules[m]; m++) {
if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {
continue;
}
module = cf->cycle->modules[m]->ctx;
mi = cf->cycle->modules[m]->ctx_index;
if (module->create_main_conf) {
ctx->main_conf[mi] = module->create_main_conf(cf);
if (ctx->main_conf[mi] == NULL) {
return NGX_CONF_ERROR;
}
}
if (module->create_srv_conf) {
ctx->srv_conf[mi] = module->create_srv_conf(cf);
if (ctx->srv_conf[mi] == NULL) {
return NGX_CONF_ERROR;
}
}
if (module->create_loc_conf) {
ctx->loc_conf[mi] = module->create_loc_conf(cf);
if (ctx->loc_conf[mi] == NULL) {
return NGX_CONF_ERROR;
}
}
}
……
}
如上代碼,對應http模塊來說,它的二維指標指向的結構為:ngx_http_conf_ctx_t;該結構中有三個 void** 型別的指標;對于main_conf、srv_conf、loc_conf三個void**指標申請記憶體為: ngx_http_max_module個void*的大小;因此http模塊的三維指標對應:main_conf、srv_conf、loc_conf型別的指標,因為這三個指標每一個都是二維指標(void**),指向的一個void* 的陣列,對于main_conf指標來說指向對應http模塊的create_main_conf函式回傳的地址,因此http模塊的四維指標對應的是create_xxx_conf函式回傳的地址,執行srv_conf、loc_conf指標同理在此不再贅述,下來看一下 http 的第一個模塊ngx_http_core_module 的 create_main_conf 函式,主要代碼如下:
static void * ngx_http_core_create_main_conf(ngx_conf_t *cf)
{
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_main_conf_t));
if (cmcf == NULL) {
return NULL;
}
……
return cmcf;
}
以上對四維指標詳細的分析了,其實對于四維指標只有http模塊用了四維;對于ngx_core_module 模塊只用了二維指標,源代碼其實實作的非常清楚,下來我通過一張圖片對本節進行一下整體梳理,梳理圖如下:

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/355127.html
標籤:其他
