nginx事件模組 -- 第四篇
阿新 • • 發佈:2018-12-26
微信公眾號:鄭爾多斯
關注可瞭解更多的Nginx知識。任何問題或建議,請公眾號留言;
關注公眾號,有趣有內涵的文章第一時間送達!
劇情回顧
上一篇文章中我們詳細介紹了Nginx
中事件模組的初始化過程。這裡簡單的回顧一下:Nginx
的worker
程序啟動之後,會首先進行worker
的初始化,在初始化過程中將遍歷呼叫所有模組的init_process
函式。與Nginx
事件機制相關的三個模組中,只有ngx_event_core_module
才實現了對應的鉤子函式ngx_event_process_init
。上一篇文章我們已經比較詳細的分析了這篇文章,但是還遺留了幾個問題,比如,epoll
epoll
是如何初始化的。
epoll初始化
首先觀察ngx_event_process_init
下面的程式碼:
for (m = 0; cycle->modules[m]; m++) {
if (cycle->modules[m]->type != NGX_EVENT_MODULE) {
continue;
}
if (cycle->modules[m]->ctx_index != ecf->use) {
continue ;
}
module = cycle->modules[m]->ctx;
if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) {
/* fatal */
exit(2);
}
break;
}
這部分程式碼就涵蓋了epoll
的初始化過程,它是如何實現的呢?
遍歷所有的模組,找到我們選擇的事件處理模組,本例中就是
ngx_epoll
,然後呼叫時間模組的action.init()
方法。
下面我們看一下ngx_epoll
的原始碼:
static ngx_event_module_t ngx_epoll_module_ctx = {
&epoll_name,
ngx_epoll_create_conf, /* create configuration */
ngx_epoll_init_conf, /* init configuration */
{
ngx_epoll_add_event, /* add an event */
ngx_epoll_del_event, /* delete an event */
ngx_epoll_add_event, /* enable an event */
ngx_epoll_del_event, /* disable an event */
ngx_epoll_add_connection, /* add an connection */
ngx_epoll_del_connection, /* delete an connection */
#if (NGX_HAVE_EVENTFD)
ngx_epoll_notify, /* trigger a notify */
#else
NULL, /* trigger a notify */
#endif
ngx_epoll_process_events, /* process the events */
ngx_epoll_init, /* init the events */
ngx_epoll_done, /* done the events */
}
};
從程式碼中可以看到,action.init()
對應於ngx_epoll_init()
,下面我們分析一下該函式
ngx_epoll_init
先看程式碼:
static ngx_int_t
ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
{
ngx_epoll_conf_t *epcf;
epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module);
if (ep == -1) {
ep = epoll_create(cycle->connection_n / 2);
if (ep == -1) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
"epoll_create() failed");
return NGX_ERROR;
}
#if (NGX_HAVE_EVENTFD)
if (ngx_epoll_notify_init(cycle->log) != NGX_OK) {
ngx_epoll_module_ctx.actions.notify = NULL;
}
#endif
#if (NGX_HAVE_FILE_AIO)
ngx_epoll_aio_init(cycle, epcf);
#endif
#if (NGX_HAVE_EPOLLRDHUP)
ngx_epoll_test_rdhup(cycle);
#endif
}
if (nevents < epcf->events) {
if (event_list) {
ngx_free(event_list);
}
event_list = ngx_alloc(sizeof(struct epoll_event) * epcf->events,
cycle->log);
if (event_list == NULL) {
return NGX_ERROR;
}
}
nevents = epcf->events;
ngx_io = ngx_os_io;
ngx_event_actions = ngx_epoll_module_ctx.actions;
#if (NGX_HAVE_CLEAR_EVENT)
ngx_event_flags = NGX_USE_CLEAR_EVENT
#else
ngx_event_flags = NGX_USE_LEVEL_EVENT
#endif
|NGX_USE_GREEDY_EVENT
|NGX_USE_EPOLL_EVENT;
return NGX_OK;
}
這部分程式碼就是epoll
初始化的程式碼,我們可以清晰的理一下思路:
- 使用
epoll_create()
建立一個epoll
例項
- 根據配置檔案中
events
的數量建立對應數量的epoll_event
結構體 - 設定一些全域性變數的值,如
nevents
,ngx_io
,ngx_event_actions
- 這裡有一個比較重要的變數就是
ngx_event_flags
,這個變數在後面經常使用到,通過除錯發現該變數的值為:NGX_USE_CLEAR_EVENT | NGX_USE_GREEDY_EVENT | NGX_USE_EPOLL_EVENT
喜歡本文的朋友們,歡迎長按下圖關注訂閱號鄭爾多斯,更多精彩內容第一時間送達