9.4 ngx_events_module核心模块

ngx_events_module模块是一个核心模块,它定义了一类新模块:事件模块。它的功能如下:定义新的事件类型,并定义每个事件模块都需要实现的ngx_event_module_t接口(参见9.1.1节),还需要管理这些事件模块生成的配置项结构体,并解析事件类配置项,当然,在解析配置项时会调用其在ngx_command_t数组中定义的回调方法。这些过程在下文中都会介绍,不过,首先还是看一下ngx_events_module模块的定义。

就像在第3章中我们曾经做过的一样,定义一个Nginx模块就是在实现ngx_modult_t结构体。这里需要先定义好ngx_command_t(决定这个模块如何处理自己感兴趣的配置项)数组,因为任何模块都是以配置项来定制功能的。ngx_events_commands数组决定了ngx_events_module模块是如何定制其功能的,代码如下。


static ngx_command_t ngx_events_commands[]={

{ngx_string("events"),

NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,

ngx_events_block,

0,

0,

NULL},

ngx_null_command

};


可以看到,ngx_events_module模块只对一个块配置项感兴趣,也就是nginx.conf中必须有的events{……}配置项。注意,这里暂时先不要关心ngx_events_block方法是如何处理这个配置项的。

作为核心模块,ngx_events_module还需要实现核心模块的共同接口ngx_core_module_t,如下所示。


static ngx_core_module_t ngx_events_module_ctx={

ngx_string("events"),

NULL,

NULL

};


可以看到,ngx_events_module_ctx实现的接口只是定义了模块名字而已,ngx_core_module_t接口中定义的create_conf方法和init_conf方法都没有实现(NULL空指针即为不实现),为什么呢?这是因为ngx_events_module模块并不会解析配置项的参数,只是在出现events配置项后会调用各事件模块去解析events{……}块内的配置项,自然就不需要实现create_conf方法来创建存储配置项参数的结构体,也不需要实现init_conf方法处理解析出的配置项。

最后看一下ngx_events_module模块的定义代码如下。


ngx_module_t ngx_events_module={

NGX_MODULE_V1,

&ngx_events_module_ctx,/module context/

ngx_events_commands,/module directives/

NGX_CORE_MODULE,/module type/

NULL,/init master/

NULL,/init module/

NULL,/init process/

NULL,/init thread/

NULL,/exit thread/

NULL,/exit process/

NULL,/exit master/

NGX_MODULE_V1_PADDING

};


可见,除了对events配置项的解析外,该模块没有做其他任何事情。下面开始介绍在解析events配置块时,ngx_events_block方法做了些什么。

9.4.1 如何管理所有事件模块的配置项

上文说过,每一个事件模块都必须实现ngx_event_module_t接口,这个接口中允许每个事件模块建立自己的配置项结构体,用于存储感兴趣的配置项在nginx.conf中对应的参数。ngx_event_module_t中的create_conf方法就是用于创建这个结构体的方法,事件模块只需要在这个方法中分配内存即可,但这个内存指针是如何由ngx_events_module模块管理的呢?下面来看一下这些事件模块的配置项指针是如何被存放的,如图9-2所示。

9.4 ngx_events_module核心模块 - 图1

图 9-2 所有事件模块配置项结构体的指针是如何管理的

每一个事件模块产生的配置结构体指针都会被放到ngx_events_module模块创建的指针数组中,可这个指针数组又存放到哪里呢?看一下ngx_cycle_t核心结构体中的conf_ctx成员,它指向一个指针数组,而这个指针数组中就依次存放着所有的Nginx模块关于配置项方面的指针。在默认的编译顺序下,从ngx_modules.c文件中可以看到ngx_events_module模块是在ngx_modules数组中的第4个位置,因此,所有进程的conf_ctx数组的第4个指针就保存着上面说过的ngx_events_module模块创建的指针数组。解释是不是有点绕?再回顾一下ngx_cycle_t结构体中的conf_ctx的定义:


void

**conf_ctx;


为什么上面代码中有4个?因为它首先指向一个存放指针的数组,这个数组中的指针成员同时又指向了另外一个存放指针的数组,所以是4个。看到conf_ctx的奥秘了吧。只有拥有了这个conf_ctx,才可以看到任意一个模块在create_conf中产生的结构体指针。同理,HTTP模块和mail模块也是这样做的,这些模块的通用接口中也有create_conf方法,其产生的指针会以相似的方式存放。

每一个事件模块如何获取它在create_conf中分配的结构体的指针呢?ngx_events_module定义了一个简单的宏来完成这个功能代码,如下。


define ngx_event_get_conf(conf_ctx,module)\

(*(ngx_get_conf(conf_ctx,ngx_events_module)))[module.ctx_index];


ngx_get_conf也是一个宏,它用来获取图9-1中第一个数组中的指针,如下所示。


define ngx_get_conf(conf_ctx,module)conf_ctx[module.index]


因此,调用ngx_event_get_conf时只需要在第1个参数中传入ngx_cycle_t中的conf_ctx成员,在第2个参数中传入自己的模块名,就可以获取配置项结构体的指针。详细内容可参见9.6.3节中使用ngx_epoll_module的ngx_epoll_init方法获取配置项的例子。