再打算正式開(kāi)始研究core模塊式,發(fā)現(xiàn)有一個(gè)很重要的變量ngx_cycle_t,一直伴隨,如果不懂ngx_cycle可能讀起代碼來(lái)回非常困難,這里就來(lái)詳細(xì)學(xué)習(xí)一下吧。本文大部分靈感來(lái)自于。 http://blog.csdn.net/livelylittlefish/article/details/7247080 和 http://blog.sina.com.cn/s/blog_677be95b0100iivi.html 謝謝作者提供很詳細(xì)的資料。
依照慣例我們直接來(lái)看下
其中,
- pathes 數(shù)組元素結(jié)構(gòu)為 ngx_path_t ;
- open_files 鏈表元素結(jié)構(gòu)為 ngx_open_file_t ;
- shared_memory 鏈表元素結(jié)構(gòu)為 ngx_shm_zone_t ;
- listening 數(shù)組元素結(jié)構(gòu)為 ngx_listening_t ,該數(shù)組用來(lái)存放監(jiān)聽(tīng)套接字。
再來(lái)看下 ngx_init_cycle函數(shù)的處理過(guò)程 :
1. 調(diào)用ngx_timezone_update()、ngx_timeofday()和ngx_time_update(0, 0)做時(shí)間校準(zhǔn) ;
2. 創(chuàng)建一個(gè)新的ngx_cycle_t變量cycle,并且初始化其大部分的成員字段,有一些是從傳入的old_cycle直接拷貝過(guò)來(lái)的,這些字段包括: log,conf_prefix,prefix,conf_file,conf_param ;
還有一些字段會(huì)判斷一下old_cycle中是否存在,如果存在,則取得這些字段的占用空間,在cycle中申請(qǐng)等大的空間,并初始化(不拷貝),否則就申請(qǐng)默認(rèn)大小的空間,這些字段有: pathes,open_files,share_memory,listening ;
還有一些字段是重新創(chuàng)建或者第一次賦值的:pool,new_log.log_level(=NGX_LOG_ERR),old_cycle(=old_cycle),hostname(gethostname);
最重要的一個(gè)字段是conf_ctx,它被初始化為ngx_max_module個(gè)void *指針,這預(yù)示著conf_ctx是所有模塊的配置結(jié)構(gòu)的指針數(shù)組;
3. 從命令行和配置文件中把所有配置更新到cycle的conf_ctx中:
首先調(diào)用ngx_conf_param把命令行中的指令(-g directives)轉(zhuǎn)換為配置結(jié)構(gòu)并把指針加入到cycle.conf_ctx中;
接著調(diào)用ngx_conf_parse(..,filename)把配置文件中的指令轉(zhuǎn)換為配置結(jié)構(gòu)并把指針加入到cycle.conf_ctx中。
ngx_conf_param最后也會(huì)調(diào)用ngx_conf_parse(..,NULL),所以配置的更新主要是在ngx_conf_parse中進(jìn)行的,這個(gè)函數(shù)中有一個(gè)for循環(huán),每次循環(huán)調(diào)用ngx_conf_read_token取得一個(gè)配置指令(以;結(jié)尾)(這里在上一節(jié)已經(jīng)詳細(xì)將結(jié)果),然后調(diào)用ngx_conf_handler處理這條指令,ngx_conf_handler每次都會(huì)遍歷所有模塊的指令集,查找這條配置指令并分析其合法性,如果指令正確,則會(huì)創(chuàng)建配置結(jié)構(gòu)并把指針加入到cycle.conf_ctx中,配置結(jié)構(gòu)的賦值是調(diào)用該指令的鉤子set完成的。
遍歷指令集的過(guò)程首先是遍歷所有的核心類模塊,若是event類的指令,則會(huì)遍歷到ngx_events_module,這個(gè)模塊是屬于核心類的,其鉤子set又會(huì)嵌套調(diào)用ngx_conf_parse去遍歷所有的event類模塊,同樣的,若是http類指令,則會(huì)遍歷到ngx_http_module,該模塊的鉤子set進(jìn)一步遍歷所有的http類模塊,mail類指令會(huì)遍歷到ngx_mail_module,該模塊的鉤子進(jìn)一步遍歷到所有的mail類模塊。要特別注意的是:這三個(gè)遍歷過(guò)程中會(huì)在適當(dāng)?shù)臅r(shí)機(jī)調(diào)用event類模塊、http類模塊和mail類模塊的創(chuàng)建配置和初始化配置的鉤子。從這里可以看出,event、http、mail三類模塊的鉤子是配置中的指令驅(qū)動(dòng)的;
4.調(diào)用所有核心類模塊的鉤子init_conf,把模塊的配置結(jié)構(gòu)作為一個(gè)參數(shù)傳入:init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index);
5. 獲得核心模塊ngx_core_dodule的配置結(jié)構(gòu),然后調(diào)用ngx_create_pidfile創(chuàng)建pid文件。獲取配置結(jié)構(gòu)的代碼:ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module),這里的ngx_get_conf是一個(gè)宏定義:#define ngx_get_conf(conf_ctx, module) <wbr>conf_ctx[module.index];</wbr>
6. 調(diào)用ngx_test_lockfile(filename,log),ngx_create_pathes(cycle,user),接著打開(kāi)errorlog文件并賦值給cycle->new_log.file:cycle->new_log.file = ngx_conf_open_file(cycle, &error_log);
7. 打開(kāi)新文件,在第2步的時(shí)候提到cycle->open_files這個(gè)鏈表是空的,只是給它預(yù)先分配了空間,并沒(méi)有數(shù)據(jù),這里之所以可能會(huì)有文件被打開(kāi),估計(jì)是前面讀配置文件的時(shí)候,調(diào)用各個(gè)鉤子的過(guò)程中,填充了這個(gè)鏈表,把ngx_open_file_t結(jié)構(gòu)變量填充進(jìn)來(lái)(結(jié)構(gòu)體中包含要打開(kāi)文件的路徑信息),這是我猜測(cè)的,之后再驗(yàn)證:)接著修改一下cycle的成員:cycle->log = &cycle->new_log;pool->log = &cycle->new_log ;
8. 創(chuàng)建共享內(nèi)存,和open_files類似,在第2步的時(shí)候cycle->share_memory也初始化為一個(gè)空的鏈表,也是預(yù)分配了空間,如果此時(shí)鏈表中已經(jīng)被填充了ngx_shm_zone_t結(jié)構(gòu)變量(其中包含需要共享內(nèi)存的尺寸和標(biāo)識(shí)等信息),那么這里就會(huì)分配共享內(nèi)存,并且調(diào)用合適的初始化鉤子初始化分配的共享內(nèi)存,每塊共享內(nèi)存都會(huì)有name標(biāo)識(shí),這里也會(huì)做一些排重,已經(jīng)分配的就不會(huì)再去分配,從對(duì)open_files和share_memory的處理過(guò)程可以看出,nginx在資源管理上是集中分配的,請(qǐng)求資源的時(shí)候分配說(shuō)明性的結(jié)構(gòu)變量,然后在恰當(dāng)?shù)臅r(shí)機(jī)才去真正分配資源;
9.
處理listening sockets,cycle->listening是ngx_listening_t結(jié)構(gòu)的數(shù)組,把cycle->listening于old_cycle->listening進(jìn)行比較,設(shè)置cycle->listening的一些狀態(tài)信息,接著調(diào)用ngx_open_listening_sockets(cycle)啟動(dòng)cycle->listening中的所有監(jiān)聽(tīng)socket,循環(huán)調(diào)用socket,bind,listen完成服務(wù)端監(jiān)聽(tīng)socket的啟動(dòng)。接著調(diào)用ngx_configure_listening_sockets(cycle)配置監(jiān)聽(tīng)socket,會(huì)根據(jù)ngx_listening_t中的狀態(tài)信息設(shè)置socket的讀寫(xiě)緩存和TCP_DEFER_ACCEPT;
10. 調(diào)用所有模塊的鉤子init_module;
11. 關(guān)閉或者刪除一些殘留在old_cycle中的資源,首先釋放不用的共享內(nèi)存,接著關(guān)閉不使用的監(jiān)聽(tīng)socket,再關(guān)閉不使用的打開(kāi)文件,最后把old_cycle放入ngx_old_cycles中,這是一個(gè)ngx_cycle_t *的數(shù)組,最后設(shè)定一個(gè)定時(shí)器,定期回調(diào)ngx_cleaner_event清理ngx_old_cycles,這里設(shè)置了30000ms清理一次。
放上一張圖
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
