Nginx 模块与其初始化代码流程分析
一、前置:
Nginx是模块化的体系结构体,大部分功能都是封装在模块当中,并且每个模块内部都静态
的定义了一个 ngx_modulet_t
结构体的变量,其内部分别定义了模块名称、模块上下文结构体、支持的
配置指令,相关回调函数等。这些模块在执行完 configure
脚本后,自动在objs/ngx_modules.c
源文件生成一个全局的ngx_modulet_t
指针数组,该数组保存了当前配置生效的所有模块列表。
二、模块初始化分析
下面根据代码逻辑分析模块及其相关配置上下文的初始化流程进行梳理分析。
- nginx.c:main()函数299行,对模块进行预初始化:
1
2
3if (ngx_preinit_modules() != NGX_OK) { //初始化模块索引以及模块名字
return 1;
}其内部初始化模块数组索引,模块名称;初始化全局变量1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16//初始化模块索引和名字
ngx_int_t
ngx_preinit_modules(void)
{
ngx_uint_t i;
for (i = 0; ngx_modules[i]; i++) {
ngx_modules[i]->index = i; //ngx_modules数组在objs/ngx_modules.c
ngx_modules[i]->name = ngx_module_names[i]; //ngx_module_names数组在objs/ngx_modules.c
}
ngx_modules_n = i;
ngx_max_module = ngx_modules_n + NGX_MAX_DYNAMIC_MODULES;
return NGX_OK;
}ngx_module_n
为当前模块总数,ngx_max_module
为系统当前模块数量,加上128个理论上支持的最大动态模块数量。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21ngx_int_t
ngx_cycle_modules(ngx_cycle_t *cycle)
{
/*
* create a list of modules to be used for this cycle,
* copy static modules to it
*/
cycle->modules = ngx_pcalloc(cycle->pool, (ngx_max_module + 1)
* sizeof(ngx_module_t *));
if (cycle->modules == NULL) {
return NGX_ERROR;
}
ngx_memcpy(cycle->modules, ngx_modules,
ngx_modules_n * sizeof(ngx_module_t *));
cycle->modules_n = ngx_modules_n;
return NGX_OK;
}
- ngx_cycle.c:ngx_init_cycle():
1.1 函数内部,为conf_ctx申请ngx_max_module sizeof(void)空间,用于保存所有模块配置
上下文结构体地址指针,没个模块的上下文结构体都不同,因此定义为void*类型。1
2
3
4
5cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *)); //模块数量 * (void*)指针大小
if (cycle->conf_ctx == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
1.2 申请一块大小能容纳元素为ngx_max_module个,ngx_module_t指针的数组,把全局变量ngx_modules
数组
拷贝到cycle->modules
1
2
3
4if (ngx_cycle_modules(cycle) != NGX_OK) { //创建modules列表,把ngx_modules的内容拷贝过来
ngx_destroy_pool(pool);
return NULL;
}
1 | ngx_int_t |
1.3 231行-246行代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
for (i = 0; cycle->modules[i]; i++) {
if (cycle->modules[i]->type != NGX_CORE_MODULE) { //只处理核心模块,其他非核心模块过滤掉
continue;
}
module = cycle->modules[i]->ctx; //核心模块上下文,ctx的结构体ngx_core_module_t和具体的内容,在每个模块实现代码都已经初始化了,
if (module->create_conf) { //只有core, regex,openssl, thread pool, google perltools模块设置了create_conf函数
rv = module->create_conf(cycle);
if (rv == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
cycle->conf_ctx[cycle->modules[i]->index] = rv; //保存在conf_ctx对应的索引位置,如果是CORE模块,rv是ngx_core_module_create_conf()返回值
}
}
对核心模块,定位其模块上下文ctx
成员,对于定义了create_conf
回调函数的模块,分别执行create_conf
方法,创建模块上下文,把其结果保存在cycle->conf_ctx
对应的索引位置。
其中模块上下文ctx
在每一个模块结构体ngx_module_t
变量内部预先定义好了。
目前只有 core
,regex
,openssl
, thread pool
, google perltools
模块设置了create_conf
回调函数。
1.3.1, ngx_code_module:
核心模块的create_conf
回调函数:ngx_core_module_create_conf
:
该函数主要功能是从内存池中申请一块ngx_core_conf_t
结构体的存储空间,并且初始化相关成员变量,最后返回该内存地址,最终该存储空间保存在cycle->conf_ctx
与模块索引对应的指针数组位置,后续可以通过cycle->conf_ctx[cycle->modules[i].index]
方式访问该地址空间。ngx_core_conf_t
用来是保存core模块支持的部分核心配置指令。具体可以参考该结构体定义:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34typedef struct {
ngx_flag_t daemon;
ngx_flag_t master;
ngx_msec_t timer_resolution;
ngx_msec_t shutdown_timeout;
ngx_int_t worker_processes;
ngx_int_t debug_points;
ngx_int_t rlimit_nofile;
off_t rlimit_core;
int priority;
ngx_uint_t cpu_affinity_auto;
ngx_uint_t cpu_affinity_n;
ngx_cpuset_t *cpu_affinity;
char *username;
ngx_uid_t user;
ngx_gid_t group;
ngx_str_t working_directory;
ngx_str_t lock_file;
ngx_str_t pid;
ngx_str_t oldpid;
ngx_array_t env;
char **environment;
ngx_uint_t transparent; /* unsigned transparent:1; */
} ngx_core_conf_t;
具体的内容设置,通过配置模块方法ngx_conf_param
和ngx_conf_parse
。
1.3.2,ngx_regex_module:正则表达式模块的create_conf
回调函数:ngx_regex_create_conf
:
该函数主要功能是从内存池中申请一块ngx_regex_conf_t
结构体的存储空间,并且初始化相关成员变量,最后返回该内存地址,最终该存储空间保存在cycle->conf_ctx
与模块索引对应的指针数组位置,后续可以通过cycle->conf_ctx[cycle->modules[i].index]
方式访问该地址空间。
该结构体只有一个成员变量。具体可以参考该结构体定义:1
2
3
4typedef struct {
ngx_flag_t pcre_jit;
} ngx_regex_conf_t;
以及为全局链表变量ngx_pcre_studies
,创建支持8个元素的存储空间。
1.3.3,ngx_openssl_module :openssl模块的create_conf
回调函数:ngx_openssl_create_conf
:
该函数主要功能是从内存池中申请一块ngx_openssl_conf_t
结构体的存储空间,并且初始化相关成员变量,最后返回该内存地址,最终该存储空间保存在cycle->conf_ctx
与模块索引对应的指针数组位置,后续可以通过cycle->conf_ctx[cycle->modules[i].index]
方式访问该地址空间。
该结构体只有一个成员变量。具体可以参考该结构体定义:1
2
3
4typedef struct {
ngx_uint_t engine; /* unsigned engine:1; */
} ngx_openssl_conf_t;
1.3.4,ngx_thread_pool_module :线程池模块的create_conf
回调函数:ngx_thread_pool_create_conf
:
该函数主要功能是从内存池中申请一块ngx_thread_pool_conf_t
结构体的存储空间,并且为其成员pools创建4个元素的数组空间,最后返回该内存地址,最终该存储空间保存在cycle->conf_ctx
与模块索引对应的指针数组位置,后续可以通过cycle->conf_ctx[cycle->modules[i].index]
方式访问该地址空间。
该结构体只有一个成员变量。具体可以参考该结构体定义:1
2
3
4typedef struct {
ngx_array_t pools;
} ngx_thread_pool_conf_t;
1.3.5,ngx_google_perftools_module :google perltools模块的create_conf
回调函数:ngx_google_perftools_create_conf
:
该函数主要功能是从内存池中申请一块ngx_google_perftools_conf_t
结构体的存储空间,最后返回该内存地址,最终该存储空间保存在cycle->conf_ctx
与模块索引对应的指针数组位置,后续可以通过cycle->conf_ctx[cycle->modules[i].index]
方式访问该地址空间。
该结构体只有一个成员变量。具体可以参考该结构体定义:1
2
3typedef struct {
ngx_str_t profiles;
} ngx_google_perftools_conf_t;
1.4, 配置文件解析:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38ngx_memzero(&conf, sizeof(ngx_conf_t));
/* STUB: init array ? */
conf.args = ngx_array_create(pool, 10, sizeof(ngx_str_t)); //10个元素的队列
if (conf.args == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log); //临时内存池
if (conf.temp_pool == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
conf.ctx = cycle->conf_ctx; //上文初始化的模块配置上下文
conf.cycle = cycle; //当前的cycle
conf.pool = pool; //当前内存池
conf.log = log; //日志
conf.module_type = NGX_CORE_MODULE; //核心模块
conf.cmd_type = NGX_MAIN_CONF; //文件配置
log->log_level = NGX_LOG_DEBUG_ALL;
if (ngx_conf_param(&conf) != NGX_CONF_OK) { // 解析'-g'选项传递的参数列表
environ = senv;
ngx_destroy_cycle_pools(&conf);
return NULL;
}
if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) { //解析配置文件'-c'选项指定的配置文件
environ = senv;
ngx_destroy_cycle_pools(&conf);
return NULL;
}
1.5 ngx_cycle.c 295行-312行:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18for (i = 0; cycle->modules[i]; i++) { //继续初始化核心模块
if (cycle->modules[i]->type != NGX_CORE_MODULE) {
continue;
}
module = cycle->modules[i]->ctx;
if (module->init_conf) { //调用init_conf进行初始化core,events模块提供了init_conf
if (module->init_conf(cycle,
cycle->conf_ctx[cycle->modules[i]->index])
== NGX_CONF_ERROR)
{
environ = senv;
ngx_destroy_cycle_pools(&conf);
return NULL;
}
}
}
调用核心模块的init_conf
回调方法,对模块进行初始化。目前只有core
,events
模块提供了init_conf
回调方法。
1.6 635行-639行:
1
2
3
4
5 if (ngx_init_modules(cycle) != NGX_OK) { //逐个模块调用init_module回调方法
/* fatal */
exit(1);
}
1 | ngx_int_t |
逐一调用模块提供的init_module
方法,对单一模块进行初始化。