Nginx源碼學(xué)習(xí)——配置項(xiàng)結(jié)構(gòu)體與指針

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

圖1:未保存任何地址的數(shù)組 .png

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:部分?jǐn)?shù)組元素保存了有效地址.png

圖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_ctxcycle變量的副本。進(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_CONFNGX_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_modulengx_set_worker_processes函數(shù)處理worker_processes配置項(xiàng)
ngx_events_modulengx_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:

圖4:數(shù)組元素作為指針直接指向配置項(xiàng)結(jié)構(gòu)體.png

對(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_moduleevents子模塊的數(shù)目越驻;令ctx指向該數(shù)組。
第三句:將ctx的值賦給conf指向的數(shù)組元素(如圖3),也就是令該數(shù)組元素內(nèi)保存的指針指向第二句中分配的指針數(shù)組缀旁。
因此有如圖5:

圖5:創(chuàng)建events模塊的配置項(xiàng)結(jié)構(gòu)體指針數(shù)組

接下來(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所示:

圖6: events模塊.png

在執(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ù)忠蝗。。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末漓拾,一起剝皮案震驚了整個(gè)濱河市阁最,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌骇两,老刑警劉巖速种,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異低千,居然都是意外死亡配阵,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)示血,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)棋傍,“玉大人,你說(shuō)我怎么就攤上這事难审√奔穑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵告喊,是天一觀(guān)的道長(zhǎng)麸拄。 經(jīng)常有香客問(wèn)我,道長(zhǎng)黔姜,這世上最難降的妖魔是什么拢切? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮秆吵,結(jié)果婚禮上失球,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好实苞,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布豺撑。 她就那樣靜靜地躺著,像睡著了一般黔牵。 火紅的嫁衣襯著肌膚如雪聪轿。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,554評(píng)論 1 305
  • 那天猾浦,我揣著相機(jī)與錄音陆错,去河邊找鬼。 笑死金赦,一個(gè)胖子當(dāng)著我的面吹牛音瓷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播夹抗,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼绳慎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了漠烧?” 一聲冷哼從身側(cè)響起杏愤,我...
    開(kāi)封第一講書(shū)人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎已脓,沒(méi)想到半個(gè)月后珊楼,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡度液,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年厕宗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片堕担。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡已慢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出照宝,到底是詐尸還是另有隱情蛇受,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布厕鹃,位于F島的核電站兢仰,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏剂碴。R本人自食惡果不足惜把将,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望忆矛。 院中可真熱鬧察蹲,春花似錦请垛、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至亚兄,卻和暖如春混稽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背审胚。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工匈勋, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人膳叨。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓洽洁,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親菲嘴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子饿自,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355