Content
0. 序
1. nginx有哪些模块?
2. nginx如何描述这些模块?
2.1 模块数据结构
2.1.1 ngx_module_t结构
2.1.2 ngx_command_t结构
2.2 模块类图
3. nginx如何组织这些模块?
3.1 全局数组ngx_modules
3.2 模块组织结构图
4. nginx的模块种类
5. nginx如何初始化这些模块?
5.1 静态初始化
5.2 动态初始化
5.2.1 index字段的初始化
5.2.2 ctx_index字段的初始化
5.2.3 其他初始化
6. 小结
0. 序
本文以nginx-1.0.4版本为例,介绍nginx的模块及其初始化。.表示nginx-1.0.4源代码目录,本文为/usr/src/nginx-1.0.4。
1. nginx有哪些模块?
要知道nginx有哪些模块,一个快速的方法就是编译nginx。编译之后,会在源代码根目录下生成objs目录,该目录中包含有ngx_auto_config.h和ngx_auto_headers.h,以及ngx_modules.c文件,当然,还有Makefile文件等。
其中,生成的ngx_modules.c文件中,重新集中申明(使用extern关键字)了nginx配置的所有模块,这些模块可通过编译前的configure命令进行配置,即设置哪些模块需要编译,哪些不被编译。如下。
很显然,这些模块均是在此处用extern进行申明,以表明其他模块可以访问,而对其本身的定义和初始化ngx_module_t结构在其对应的.c文件中进行。例如,ngx_core_module模块便是在./src/core/nginx.c文件中定义并进行静态初始化。实际上,ngx_core_module是一个全局的结构体对象,其他模块类同。如下。
2. nginx如何描述这些模块?
2.1 模块数据结构
2.1.1 ngx_module_t结构
nginx的模块化架构最基本的数据结构为ngx_module_t,因此,此处,我们先分析这个结构,在./src/core/ngx_conf_file.h文件中定义。如下,//后的内容为笔者加入的注视。
其中,init_master, init_module, init_process, init_thread, exit_thread, exit_process, exit_master分别在初始化master、初始化模块、初始化工作进程、初始化线程、退出线程、退出工作进程、退出master时被调用。
2.1.2 ngx_command_t结构
模块的命令集commands指向一个ngx_command_t结构数组,在./src/core/ngx_conf_file.h文件中定义。如下,//后的内容为笔者加入的注视。
2.2 模块类图
nginx为C语言开发的开源高性能web server,其代码中大量使用了callback方式,例如模块结构ngx_module_t中的init_master等。实际上,我们可以将ngx_module_t看作C++的一个类,其中的数据字段便是其属性,而那些callback便是该类的操作。
——这应该就是nginx的模块化思想。画出的ngx_module_t的类图如下。

3. nginx如何组织这些模块?
3.1 全局数组ngx_modules
由第1节,我们知道,nginx拥有几十个模块,那么,这些模块是如何组织的呢?
——保存在一个全局指针数组ngx_modules[]中,数组的每一个元素均为一个全局ngx_module_t对象的指针。如下。请参考./objs/ngx_modules.c文件中的定义。
3.2 模块组织结构图
共44个模块,这些模块的组织结构图如下所示,因模块较多,图中只画出一部分有代表性的重要模块。

4. nginx的模块种类
在对全局数组ngx_modules进行初始化时,即对每一个模块进行了静态初始化。其中对模块的type字段的初始化是通过以下4个宏进行的。
(1) 文件./src/core/ngx_conf_file.h
(2) 文件./src/event/ngx_event.h
(3) 文件./src/http/ngx_http_config.h
即模块种类宏,定义为一个十六进制的数,这个十六进制的数就是其类型对应的ASCII码。因此,nginx共有4种类型的模块,分别为"CORE","CONF","EVNT","HTTP"。
实际上,如果在configure阶段,使用了"--with-mail"参数,mail模块将被编译进来,其对应的宏如下。
因此,严格来讲,nginx有5中类型的模块,"CORE","CONF","EVNT","HTTP","MAIL"。
5. nginx如何初始化这些模块?
5.1 静态初始化
即编译期间完成的数据成员初始化。记mname为某个模块的名字,其静态初始化过程如下。
(1) 用宏NGX_MODULE_V1初始化前7个字段
(2) 用全局对象ngx_mname_module_ctx的地址初始化ctx指针
(3) 用全局数组ngx_mname_commands[]初始化commands指针
(4) 用宏NGX_CORE_MODULE等初始化type字段
(5) 初始化init_master等callback
(6) 用宏NGX_MODULE_V1_PADDING初始化最后8个字段
由此可见,在定义该模块(全局结构对象)时,将其ctx_index和index均初始化为0。因此,模块的静态初始化(数据成员初始化)实际上只是对模块上下文、模块命令集和模块类型进行初始化。
5.2 动态初始化
即nginx运行(启动)初期,对模块本身的初始化。
5.2.1 index字段的初始化
对各个模块的index字段的初始化是在main函数中进行的,如下。
可见,该for-loop执行后,每个模块的index值便是其在ngx_modules[]数组中的下标值,且全局变量ngx_max_module为模块个数,对于本例来讲,ngx_max_module=44。
5.2.2 ctx_index字段的初始化
(1) "EVNT"类型的模块
(2) "HTTP"类型的模块
(3) "MAIL"类型的模块
5.2.3 其他初始化
其他的初始化工作,将在nginx启动及其进程启动分析中介绍。
6. 小结
本文主要讲述了nginx的模块及其初始化,包括所有模块的组织,及模块的静态初始化和部分动态初始化。
Reference
nginx-1.0.4源码