nginx事件模組 -- 第一篇

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

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

事件機制

下面是我們對nginx事件相關的配置,如下:

1events {
2    worker_connections  1024;
3    use epoll;
4}
複製程式碼

我們明確的使用了epoll機制,在nginx中,和事件相關的模組一共有三個,分別為ngx_events_modulengx_event_core_modulengx_epoll_module
本篇文章介紹ngx_events_module模組。

ngx_events_module

該模組是nginx中引入事件機制的模組,我們可以從ngx_events.c檔案中找到與ngx_events_module相關的配置,如下:

 1static ngx_command_t  ngx_events_commands[] = {
2
3    { ngx_string("events"),
4      NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
5      ngx_events_block,
6      0,
7      0,
8      NULL },
9
10      ngx_null_command
11};
12
13
14static ngx_core_module_t  ngx_events_module_ctx = {
15    ngx_string("events"),
16    NULL,
17    ngx_event_init_conf
18};
19
20
21ngx_module_t  ngx_events_module = {
22    NGX_MODULE_V1,
23    &ngx_events_module_ctx,                /* module context */
24    ngx_events_commands,                   /* module directives */
25    NGX_CORE_MODULE,                       /* module type */
26    NULL,                                  /* init master */
27    NULL,                                  /* init module */
28    NULL,                                  /* init process */
29    NULL,                                  /* init thread */
30    NULL,                                  /* exit thread */
31    NULL,                                  /* exit process */
32    NULL,                                  /* exit master */
33    NGX_MODULE_V1_PADDING
34};
35
36typedef struct {
37    ngx_str_t             name;
38    void               *(*create_conf)(ngx_cycle_t *cycle);
39    char               *(*init_conf)(ngx_cycle_t *cycle, void *conf);
40ngx_core_module_t;
複製程式碼

從上面的配置中我們可以得到如下資訊:

  • ngx_events_module 是一個核心模組 (NGX_CORE_MODULE型別)
  • ngx_events_module 只解析一個命令,即events這個NGX_BLOCK命令,並且不帶引數
  • ngx_events_modulecreate_conf()函式為空,它只有init_conf()函式
  • 當遇到events指令的時候,呼叫 ngx_event_block()函式進行解析處理

解析events指令

我們在前面的文章中介紹過,配置檔案的解析是在ngx_init_cycle()函式中完成的。我們再次把這部分程式碼摘出來,如下:

1cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));
2    if (cycle->conf_ctx == NULL) {
3        ngx_destroy_pool(pool);
4        return NULL;
5    }
複製程式碼

這裡分配conf_ctx的記憶體空間,然後執行如下的程式碼:

 1for (i = 0; cycle->modules[i]; i++) {
2        if (cycle->modules[i]->type != NGX_CORE_MODULE) {
3            continue;
4        }
5
6        module = cycle->modules[i]->ctx;
7
8        if (module->create_conf) {
9            rv = module->create_conf(cycle);
10            if (rv == NULL) {
11                ngx_destroy_pool(pool);
12                return NULL;
13            }
14            cycle->conf_ctx[cycle->modules[i]->index] = rv;
15        }
16    }
複製程式碼

遍歷所有的NGX_CORE_MODULE型別的模組,呼叫他們的create_conf()方法,並且賦值給cycle->conf_ctx,上面分析過,ngx_event_module並沒有create_conf()方法,所以這部分程式碼對ngx_event_module沒有影響。

ngx_events_block

下面我麼分析一下ngx_events_block()函式,這個函式的作用就是解析events指令,程式碼如下:

 1static char *
2ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3
{
4    char                 *rv;
5    void               ***ctx;
6    ngx_uint_t            i;
7    ngx_conf_t            pcf;
8    ngx_event_module_t   *m;
9
10    if (*(void **) conf) {
11        return "is duplicate";
12    }
13
14    /* count the number of the event modules and set up their indices */
15
16    ngx_event_max_module = ngx_count_modules(cf->cycle, NGX_EVENT_MODULE);
17
18    ctx = ngx_pcalloc(cf->pool, sizeof(void *));
19    if (ctx == NULL) {
20        return NGX_CONF_ERROR;
21    }
22
23    *ctx = ngx_pcalloc(cf->pool, ngx_event_max_module * sizeof(void *));
24    if (*ctx == NULL) {
25        return NGX_CONF_ERROR;
26    }
27
28    *(void **) conf = ctx;
29
30    for (i = 0; cf->cycle->modules[i]; i++) {
31        if (cf->cycle->modules[i]->type != NGX_EVENT_MODULE) {
32            continue;
33        }
34
35        m = cf->cycle->modules[i]->ctx;
36
37        if (m->create_conf) {
38            (*ctx)[cf->cycle->modules[i]->ctx_index] =
39                                                     m->create_conf(cf->cycle);
40            if ((*ctx)[cf->cycle->modules[i]->ctx_index] == NULL) {
41                return NGX_CONF_ERROR;
42            }
43        }
44    }
45
46    pcf = *cf;
47    cf->ctx = ctx;
48    cf->module_type = NGX_EVENT_MODULE;
49    cf->cmd_type = NGX_EVENT_CONF;
50
51    rv = ngx_conf_parse(cf, NULL);
52
53    *cf = pcf;
54
55    if (rv != NGX_CONF_OK) {
56        return rv;
57    }
58
59    for (i = 0; cf->cycle->modules[i]; i++) {
60        if (cf->cycle->modules[i]->type != NGX_EVENT_MODULE) {
61            continue;
62        }
63
64        m = cf->cycle->modules[i]->ctx;
65
66        if (m->init_conf) {
67            rv = m->init_conf(cf->cycle,
68                              (*ctx)[cf->cycle->modules[i]->ctx_index]);
69            if (rv != NGX_CONF_OK) {
70                return rv;
71            }
72        }
73    }
74
75    return NGX_CONF_OK;
76}
複製程式碼

該函式的執行流程如下:

  • 計算當前有多少個NGX_EVENT_MODULE型別的模組,我們這裡的例子中有兩個該型別的模組
  • 分配記憶體空間
  • 呼叫所有NGX_EVENT_MODULE型別模組的create_conf()方法
  • 遞迴解析events塊指令的內部指令,比如use,worker_connections等指令
  • 呼叫所有 NGX_EVENT_MODULE型別模組的init_conf()方法

上面就是ngx_events_block()方法的執行流程。這個方法很簡單,因為牽涉到ngx_event_core_modulengx_epoll_module,所以下一節我們詳細介紹一下這兩個事件模組。


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

鄭爾多斯
鄭爾多斯

相關文章