nginx事件模組-- 第四篇

鄭爾多斯發表於2018-12-25

微信公眾號:鄭爾多斯
關注可瞭解更多的Nginx知識。任何問題或建議,請公眾號留言;
關注公眾號,有趣有內涵的文章第一時間送達!

劇情回顧

上一篇文章中我們詳細介紹了Nginx中事件模組的初始化過程。這裡簡單的回顧一下:Nginxworker程式啟動之後,會首先進行worker的初始化,在初始化過程中將遍歷呼叫所有模組的init_process函式。與Nginx事件機制相關的三個模組中,只有ngx_event_core_module才實現了對應的鉤子函式ngx_event_process_init。上一篇文章我們已經比較詳細的分析了這篇文章,但是還遺留了幾個問題,比如,epoll是如何初始化的,時間定時器是如何初始化的。本篇文章就分析一下epoll是如何初始化的。

epoll初始化

首先觀察ngx_event_process_init下面的程式碼:

 1for (m = 0; cycle->modules[m]; m++) {
2        if (cycle->modules[m]->type != NGX_EVENT_MODULE) {
3            continue;
4        }
5
6        if (cycle->modules[m]->ctx_index != ecf->use) {
7            continue;
8        }
9
10        module = cycle->modules[m]->ctx;
11
12        if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) {
13            /* fatal */
14            exit(2);
15        }
16
17        break;
18    }
複製程式碼

這部分程式碼就涵蓋了epoll的初始化過程,它是如何實現的呢?

遍歷所有的模組,找到我們選擇的事件處理模組,本例中就是ngx_epoll,然後呼叫時間模組的action.init()方法。

下面我們看一下ngx_epoll的原始碼:

 1static ngx_event_module_t  ngx_epoll_module_ctx = {
2    &epoll_name,
3    ngx_epoll_create_conf,               /* create configuration */
4    ngx_epoll_init_conf,                 /* init configuration */
5
6    {
7        ngx_epoll_add_event,             /* add an event */
8        ngx_epoll_del_event,             /* delete an event */
9        ngx_epoll_add_event,             /* enable an event */
10        ngx_epoll_del_event,             /* disable an event */
11        ngx_epoll_add_connection,        /* add an connection */
12        ngx_epoll_del_connection,        /* delete an connection */
13#if (NGX_HAVE_EVENTFD)
14        ngx_epoll_notify,                /* trigger a notify */
15#else
16        NULL,                            /* trigger a notify */
17#endif
18        ngx_epoll_process_events,        /* process the events */
19        ngx_epoll_init,                  /* init the events */
20        ngx_epoll_done,                  /* done the events */
21    }
22};
複製程式碼

從程式碼中可以看到,action.init()對應於ngx_epoll_init(),下面我們分析一下該函式

ngx_epoll_init

先看程式碼:

 1static ngx_int_t
2ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
3
{
4    ngx_epoll_conf_t  *epcf;
5
6    epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module);
7
8    if (ep == -1) {
9        ep = epoll_create(cycle->connection_n / 2);
10
11        if (ep == -1) {
12            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
13                          "epoll_create() failed");
14            return NGX_ERROR;
15        }
16
17#if (NGX_HAVE_EVENTFD)
18        if (ngx_epoll_notify_init(cycle->log) != NGX_OK) {
19            ngx_epoll_module_ctx.actions.notify = NULL;
20        }
21#endif
22
23#if (NGX_HAVE_FILE_AIO)
24        ngx_epoll_aio_init(cycle, epcf);
25#endif
26
27#if (NGX_HAVE_EPOLLRDHUP)
28        ngx_epoll_test_rdhup(cycle);
29#endif
30    }
31
32    if (nevents < epcf->events) {
33        if (event_list) {
34            ngx_free(event_list);
35        }
36
37        event_list = ngx_alloc(sizeof(struct epoll_event) * epcf->events,
38                               cycle->log);
39        if (event_list == NULL) {
40            return NGX_ERROR;
41        }
42    }
43
44    nevents = epcf->events;
45
46    ngx_io = ngx_os_io;
47
48    ngx_event_actions = ngx_epoll_module_ctx.actions;
49
50#if (NGX_HAVE_CLEAR_EVENT)
51    ngx_event_flags = NGX_USE_CLEAR_EVENT
52#else
53    ngx_event_flags = NGX_USE_LEVEL_EVENT
54#endif
55                      |NGX_USE_GREEDY_EVENT
56                      |NGX_USE_EPOLL_EVENT;
57
58    return NGX_OK;
59}
複製程式碼

這部分程式碼就是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

喜歡本文的朋友們,歡迎長按下圖關注訂閱號鄭爾多斯,更多精彩內容第一時間送達

鄭爾多斯
鄭爾多斯

相關文章