讀完之前的學習筆記,相信已經對nginx的啟動流程有了一定的認識,從這一節起我們想深入各個模組,學習各個模組的內的主要操作。
本文來自於:http://blog.csdn.net/lengzijian/article/details/7598996
今天我們就來學習下event模組,在之前的啟動裡多次提到了各個模組的鉤子函數,我們先來回想一下關於event模組鉤子函數的執行,也是event模組啟動的步驟:
1.創建韎
該方法,主要是創建了一個ngx_event_conf_t結構體,並且分配記憶體空間。
2.讀取設定檔:
例如讀取的檔案有如下行:
[cpp] view
plaincopyprint?
events
- {
- use oll; ;
- }
這個地方的events是block指令,在大括號內可以配置很多指令,這些指令定義在src/event/ngx_event.c中
[cpp] view
plaincopyprint?
static
ngx_command_t ngx_event_core_commands[] = {
x_string(
"worker_connections"
), - NGX_EVENT_CONF|NGX_CONF_TAKE1, NGX_EVENT_CONF|NGX_CONF_TAKE1, NGX_EVENT_CONF|NGX_CONF_TAKE1, NGX_EVENT_CONF|NGX_CONF1KE1, s,
- 0,
- 0, ...(此處省略)
- .
- NGX_EVENT_CONF|NGX_CONF_TAKE1,
- 0,
- 0,
-
{ ngx_string("use"
- ),
-
NGX_EVENT_CONF|NGX_CONF_TAKE1, 0,
-
0, ull_command
-
};
-
- 當解析到events是會回呼如下函數:
-
[cpp] view
plaincopyprint?
- src/event/ngx_event.c
-
static ngx_conf_t *cf , ngx_command_t *cmd, void *conf)
-
{ char
- 無效
***ctx; -
ngx_conf_t pcf;
- _ m;
-
/*統計事件模組的數量並設定其索引*/
-
-
ngx_event_max_module = 0;
-
for- (i = 0; ngx_modules[i]; i++) (ngx_modules[i]->type != NGX_ EVENT_MODULE) {
- 繼續;
- }
- ngx_modules[i]->ctx_index = ngx_event_max_module++;
- }
- ctx = ngx_pcalloc(cf-> pool, sizeof(void
*));
-
return- NGX_CONF_ERROR;
-
- //每個事件模組分配空間,用於保存回應配置結構的位址
- *ctx = ngx_pcalloc( cf->pool, ngx_event_max_module * sizeof(
void- *)); {
- return NGX_CONF_ERROR;
} -
- for (i = 0; ngx_modules[i]; i++ ) {
- if (ngx_modules[i]- 繼續;
- }
-
- m = ngx_modules[i]-dx _conf鉤子函數,用於建立設定結構
-
if
(m->create_conf) { -
,*)[
if- ((*ctx )[ngx_modules[i]->ctx_index] == NULL) {
-
}
-
pcf = *cf; cf->ctx = ctx; cf->cmd_type = NGX_EVENT_CONF; - //由於events為block指令,events域下方還可以設定許多其他指令,
- //例如之前提起的use等,現在開始解析events block中的指令,完成工作初始化。
rv = ngx_conf_parse(cf, NULL); -
- if
(rv != NGX_CONF_OK) - return rv;
- = 0; ngx_modules[i]; i++) {
-
if- (ngx_modul (ngx_modul. type != NGX_EVENT_MODULE) {
-
} - m = ngx_modules[i]->ctx; init_conf函數,初始化配置結構
- if rv = m->init_conf(cf->cycle, (*ctx)[ngx_modules[i] ->ctx_index]);
- if
(rv - return rv;
} - }
-
return NGX_CONF_OK;
ngx_events_block()函數中最重要的一個過程就是呼叫ngx_conf_parse(cf, NULL),此處呼叫ngx_conf_parse()的作用就是完成設定檔中events{}這個block的解析,從而呼叫其下所有的設定檔指令的回呼函數,完成解析設定檔的初始化工作。但這裡我個人有個問題,待問完前輩之後,在指明問題和答案******。
2.初始化conf(init_conf)
ngx_event_init_conf()
該方法,主要是初始化ngx_event_conf_t結構體。
3.ngx_event_module_init
從名字上看是模組的初始化操作,但是縱觀各個模組原始碼,發現很多模組都沒有init回呼函數。這裡本人也在糾結為什麼,希望在學完全部代碼後,能找到答案。
[cpp] view
plaincopyprint?
- src/event/ngx_event.c
-
static ngx_int_t
- {
- 無效
- u_char *共享;
- size_t
尺寸, cl; - ngx_shm_t shm;
- ngx_time_t *tp;
- ngx_core_conf_t *ccf;
- ngx_event_conf_t *ecf;
-
- // = ngx_get_conf(cycle->conf_ctx, ngx_事件模組);
-
if
- (cf == NULL) {
-
- 「設定中沒有「事件」部分」); 「配置中沒有「事件」部分」);
「 -
回
- NGX_ERROR;
- //取得ngx_event_core_module模組的設定結構
- ecf = (cf.
- //檢視是否為event中的模組,例如使用。 。 。 。
- if (!ngx_test_config && ngx_process ngx_log_error(NGX_LOG_NOTICE, cycle->script 0,
- event method", ecf->name);
-
}
- ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
-
//將
ngx_timer_resolution = ccf->timer_resolution;
- #if ! (NGX_WIN32)
{ -
struct- rlimit rlmt;
- 拾取man getrlimit
- if
(getrlimit ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, - RLIMIT_NOFILE) failed, ignored");
-
- } else {
- //如果 //且ngx_core_module最大連線數無限制
- /或ngx_event_core_module連線數大於ngx_core_module最大連線數
-
&& (ccf->rlimit_nofile == NGX_CONF_UNSET
|| ecf->connections > (ngx_uint_t) ccf->親素-
limit = (ccf->rlimit_nofile == NGX_CONF_UNSET (ngx_int_t) rlmt.rlim_cur : ccf ->rlimit_nofile;
-
"%ui worker_connections are - "open file resource limit: %i",
ecf->connections, limit); } } }
- #endif /* !(NGX_WIN32) */
-
//如果關閉了master進程,就返回是單一工作方式,
- //之後的操作時建立共享記憶體實作鎖等工作,單進程不需要。
- if (ccf->master == 0) { NGX_OK;
-
} 已經有accept互斥了,不需要再重複創建了
-
-
if
- (ngx_accept_mutex_ptrif (ngx_accept_mutex_ptr)) return NGX_OK;
- }
-
- /* cl should be equal or bigger
- cl = 128;
-
//在這裡創造sizeize大小的大小的大小共享內存,這塊共享記憶體將被分成三段
- size = cl
-
+ cl /*
+ cl; - /* ngx_temp_number */ //準備共享內存,大小為size,命名nginx_shared_zone,
- shm.size
- shm.size shm.size
- shm.name.len = sizeof("nginx_shared_zone"
); *) - "nginx_shared_zone";
shm .log = cycle->log; -
if (ngx_shm_alloc(&shm) != NGX_OK ) {
- return NGX_ERROR; //取得起始位址保存 shared = shm.addr;
- //accept互斥體取得共享記憶體的第一段cl大小記憶體
- ngx_accept_mutex.spin = (ngx_uint_t) -1;
-
/*創建accept互斥體-
- 就是使用的這段共享記憶體來實現accept互斥體;否則,將使用檔案鎖定
- 來實現accept互斥體。
-
- accept 互斥體的作用是:避免驚群與實現worker進程的負載平衡。
-
- */ (ngx_shmtx_create(&ngx_accept_mutex, shared, cycle->lock_file.data)
- {
return-
Sharp ngx_atomic_t *) (shared + 1 * cl); - , 1);
-
- ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_log_debug2(NGX_LOG_DEBUGcleEVENT, cycy-> log, 0,
- ngx_connection_counter, *ngx_connection_counter); ngx_connection_counter, *ngx_connection_counter);
-
ngx_temp_number = (ngx_atomic_t *) (shared + 2 tp = ngx_timeofday();
-
- ngx_
-
return
- 4.ngx_event_process_init在先前的worker進程分析中有提到過,當創建了一個worker進程後,worker進程首先就會做進程的初始化工作,此時會呼叫ngx_event_process_init函數。
- [cpp] view
plaincopyprint?
- src/event/ngx_event.c
- static ngx_int_t o_p )
- {
- ngx_uint_t ngx_event_t *rev, *wev;
- ngx_listening_t *c, *next, *old;
- ngx_core_conf_t *ccf;
- ngx_event_module_t *module;
-
- //與先前相同,取得反應模組 (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
- ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
- ,已經創建了accept_mutex
- //才打開accept互斥體
- if
(ccf->master && ccf->worker_processes -
ngx_use_accept_mutex = 1; //使用互斥物
-
- ngx_accept_mutex_held = 0; ngx_accept_mutex_delay = ecf->accept_mutex_delay;//爭搶互斥體失敗後,等待下次爭搶時間間隔
-
} ngx_use_accept_mutex = 0;
-
}
- //先未講
-
#endif器,此處將會建立一顆紅黑樹,來維護計時器,之後會詳細解說
-
if (ngx_event_timer_init
return- NGX_ERROR;
- } }
-
for
- (m = 0; ngx_modules[m]; m++) { NGX_EVENT_MODULE模組
- if (ngx_modules[m]->type != NGX_EVENT_MODULE) {
- }
- //非use配置指令指定的模組跳過,linux預設epoll es[m]->ctx_index != ecf->use) {
- continue;
- module = ngx_modules[m]->ctx;
-
由於nginx實現了許多事件模組 (這些模組位於src/event/modules目錄中),所以nginx對時間模組進行了一層抽象,-
- 方便了不同的系統使用不同的事件模型,也方便擴充新的時間模型,我們的重點應該
-
- _ module->actions結構封裝了
- epoll的所有介面函數。 nginx就是透過actions結構將epoll註冊到事件抽象層。
- actions的種類是ngx_event_action_t,位於src/event/ngx_event.h
- 這些特定的內容會在下一節中重點解說。
-
- */
- if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) {
- /* fatal */
-
exit(2);
-
break- ;
- 內容
- //創建全域的ngx_connection_t數組,保存所有的connection worker進程中執行的,所以每個worker都有自己的connection陣列
- cycle->connections =
t) * cycle->connection_n, cycle->log); - if
( cycle->connections == NULL) { -
return
-
- c = cycle->connections; 🎠 //建立一個讀取事件陣列
-
cycle->read_events = ngx_alloc(size (ngx_event_t) if
- (cycle->read_events == NULL) { }
-
- rev = cycle->read_events; for
(i = 0; i connection_n; i++) {
- rev[i].instance = 1;
- #if (NGX_THREADS)
- rev[i].lock = own_lock = &c[i].lock; # endif
- }
- //建立一個寫事件佇列
-
cycle->connection_n,
-
if- (cycle->write_events == NULL) { OR;
- }
- cle.
- for
(i = 0; i 連接_n; i++) { = 1;
- #if (NGX_THREADS)
wev[i].lock = &c[i].lock;
- #endif
} i = 循環- -
//初始化連接佇列
- do
- do
i--; -
c[i].read = &cycle->read_events[i]; - c [i].write = &cycle->write_events[i];
c[i].fd = (ngx_socket_t) c[i].fd = (ngx_socket_t) c[i].fd = (ngx_socket_t) c - 下一個= &c[i];
-
-
#if (NGX_THREADS)
-
- #endif
-
- }while (i);
-
- ->free_connection_n = cycle->connection_n;
-
-
/* forforforforforforforfor號each listening socket */
- //每個監聽套接字從一個接合 ls = cycle->listening.elts;
- for (i = 0; i listening.nelts; i++) { 在ton中取得新的連線solt
- c = ngx_get_connection(ls[i].fd, cycle->log);
- return
NGX_ERROR; -
NGX_ERROR;
- }
-
- c->log = &ls[i].log; c->聽= &ls[i];
- ls[i].connection = c ;
-
- rev = c->閱讀; ->log = c->log;
-
rev->accept = 1; //讀取時間問
//簡潔-
#endif-
-
if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) & NGX_USE_
IOC- P_EVENT)) if
(ls[i].previous) { -
- * 刪除舊的接受事件綁定 * 舊循環讀取事件陣列
- 的舊式 = ls [i].previous->連接;
-
NGX_CLOSE_EVENT)
-
{ 回復
- NGX_ERR或; }
- }
- }
-
-
//登錄監聽套介面毒事件的回呼函數 rev->handler = ngx_event_accept;
暫時不將監聽套接字放入epoll中,而是-
-
//worker - if (ngx_use_accept_mutex) {
- continue;
- }
- if
(ngx_event_flags & NGX_USE_RTSIG_EVENT) { -
- if
(ngx_add_conn(c) == NGX_ERROR) - return NGX_ERROR;
-
} else {
-
//沒有使用accept互斥體,因此將此監聽套接字放入epoll中。
-
if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {
- return NGX_ERROR;
- }
} -
- #endif
- return NGX_OK;
}
- } ,事件驅動的初始化已經完成。
以上就介紹了nginx 原始碼學習筆記(二十)—— event 模組一 ——初始化,包括了IOC,計數器方面的內容,希望對PHP教程有興趣的朋友有所幫助。 -