配置指令-events
在属于2. 指令类型1.该指令只能出现在主配置上下文(main context) 中。主配置上下文指的是 Nginx 配置文件的最顶层,即不在任何块内部的位置。该指令必须带一个配置块(即花括号 ),用于包含子指令。语法特征:指令后跟 ,形成一个配置上下文块。该指令不接受任何参数(除了后面的块)。非法写法:4. 三者组合的完整语义等价于告诉 Nginx:函数是 Nginx 配置解析阶段用于处理配置块
1. 定义
在./nginx-1.24.0/src/event/ngx_event.c
属于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
};
static ngx_core_module_t ngx_events_module_ctx = {
ngx_string("events"),
NULL,
ngx_event_init_conf
};
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
};
2. 指令类型
NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
1. NGX_MAIN_CONF
该指令只能出现在主配置上下文(main context) 中。
主配置上下文指的是 Nginx 配置文件的最顶层,即不在任何 {} 块内部的位置。
2. NGX_CONF_BLOCK
该指令必须带一个配置块(即花括号 {}),用于包含子指令。
语法特征:指令后跟 { ... },形成一个配置上下文块。
3. NGX_CONF_NOARGS
该指令不接受任何参数(除了后面的 {} 块)。
- 语法要求:指令名后直接跟
{,中间不能有其他 token。 - 合法写法:
events { ... } - 非法写法:
events off { ... } # ❌ 多余参数 "off" events 10 { ... } # ❌ 多余参数 "10"
4. 三者组合的完整语义
NGX_MAIN_CONF | NGX_CONF_BLOCK | NGX_CONF_NOARGS
等价于告诉 Nginx:
“
events是一个不带任何参数的块指令,只能出现在配置文件的最顶层(主上下文),其后必须紧跟一个{}配置块,用于定义事件处理相关参数。”
3. ngx_events_block
static char *
ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *rv;
void ***ctx;
ngx_uint_t i;
ngx_conf_t pcf;
ngx_event_module_t *m;
if (*(void **) conf) {
return "is duplicate";
}
/* count the number of the event modules and set up their indices */
ngx_event_max_module = ngx_count_modules(cf->cycle, NGX_EVENT_MODULE);
ctx = ngx_pcalloc(cf->pool, sizeof(void *));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}
*ctx = ngx_pcalloc(cf->pool, ngx_event_max_module * sizeof(void *));
if (*ctx == NULL) {
return NGX_CONF_ERROR;
}
*(void **) conf = ctx;
for (i = 0; cf->cycle->modules[i]; i++) {
if (cf->cycle->modules[i]->type != NGX_EVENT_MODULE) {
continue;
}
m = cf->cycle->modules[i]->ctx;
if (m->create_conf) {
(*ctx)[cf->cycle->modules[i]->ctx_index] =
m->create_conf(cf->cycle);
if ((*ctx)[cf->cycle->modules[i]->ctx_index] == NULL) {
return NGX_CONF_ERROR;
}
}
}
pcf = *cf;
cf->ctx = ctx;
cf->module_type = NGX_EVENT_MODULE;
cf->cmd_type = NGX_EVENT_CONF;
rv = ngx_conf_parse(cf, NULL);
*cf = pcf;
if (rv != NGX_CONF_OK) {
return rv;
}
for (i = 0; cf->cycle->modules[i]; i++) {
if (cf->cycle->modules[i]->type != NGX_EVENT_MODULE) {
continue;
}
m = cf->cycle->modules[i]->ctx;
if (m->init_conf) {
rv = m->init_conf(cf->cycle,
(*ctx)[cf->cycle->modules[i]->ctx_index]);
if (rv != NGX_CONF_OK) {
return rv;
}
}
}
return NGX_CONF_OK;
}
ngx_events_block 函数
是 Nginx 配置解析阶段用于处理 events 配置块的核心函数。
用于在解析配置文件时解析 events 指令
1. 函数签名
static char *
ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
这是一个静态函数,返回 char*
参数:
cf:当前配置上下文(包含解析器状态、内存池、模块列表等)。cmd:当前正在处理的配置指令(即events指令)。conf:指向父级配置结构中用于存储events配置的指针(通常是一个void**)。
2. 局部变量
{
char *rv;
void ***ctx;
ngx_uint_t i;
ngx_conf_t pcf;
ngx_event_module_t *m;
声明局部变量:
rv:用于存储子函数返回值ctx:三层指针(void***),用于指向一个数组,该数组的每个元素是一个事件模块的配置结构体指针。i:循环计数器。pcf:保存cf的原始状态(用于配置解析后恢复上下文)。m:指向具体事件模块的ngx_event_module_t结构。
3. 重复性检查
if (*(void **) conf) {
return "is duplicate";
}
防止重复配置:检查 conf 是否已非空(即是否已经解析过 events 块)。
如果已存在,返回错误 "is duplicate"(Nginx 配置中不允许多个 events 块)。
注意:
conf是void**类型,*(void**)conf是void*,用于存放ctx。
4. 统计 event 类型模块数量并分配索引
/* count the number of the event modules and set up their indices */
ngx_event_max_module = ngx_count_modules(cf->cycle, NGX_EVENT_MODULE);
调用 ngx_count_modules 统计 类型为 NGX_EVENT_MODULE 的模块数量,并保存在全局变量 ngx_event_max_module 中。
这个值用于后续分配数组空间(每个事件模块一个配置指针)。
5. 为配置结构体分配内存
ctx = ngx_pcalloc(cf->pool, sizeof(void *));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}
*ctx = ngx_pcalloc(cf->pool, ngx_event_max_module * sizeof(void *));
if (*ctx == NULL) {
return NGX_CONF_ERROR;
}
*(void **) conf = ctx;
在 cf->pool 内存池中分配一个数组,
其每一个元素都是一个 指针(指向一个 事件模块 的配置结构体)ngx_event_max_module 是 事件类型模块的最大数量
这个数组的首地址保存在 ctx 指向的内存中,ctx 的地址又保存在 conf 指向的内存中
为什么不直接将数组的首地址保存到 conf 指向的内存中?
为了 和 HTTP 模块保持一致,方便在之后统一处理
一个 HTTP 模块的配置结构体是 4 层 指针,
event 模块也要 4 层,conf 是第一层ctx 是第二层
数组首地址是第三层
数组中的一个元素是第四层
经过这 4 层,在第 4 层的数组中获得的元素是一个指针,
这个指针才指向一个具体的 模块的配置结构体
所有的 event 类型的配置结构体的地址 收集在一起放在 *ctx 这个数组中,
每个 event 模块的 ctx_index 记录的就是这个模块在 数组中 所属位置的索引
6. 为每个事件模块创建配置结构体
for (i = 0; cf->cycle->modules[i]; i++) {
if (cf->cycle->modules[i]->type != NGX_EVENT_MODULE) {
continue;
}
遍历所有已加载的模块(cf->cycle->modules 是模块指针数组,以 NULL 结尾)。
跳过非事件模块。
m = cf->cycle->modules[i]->ctx;
获取当前事件模块的上下文(即 ngx_event_module_t 结构体指针)。
if (m->create_conf) {
(*ctx)[cf->cycle->modules[i]->ctx_index] =
m->create_conf(cf->cycle);
if ((*ctx)[cf->cycle->modules[i]->ctx_index] == NULL) {
return NGX_CONF_ERROR;
}
}
}
如果模块实现了 create_conf 回调函数:
调用它来创建该模块的 配置结构体
将返回的配置指针存入 (*ctx)[ctx_index]。ctx_index 是模块在事件模块中的唯一索引
*ctx 是前面分配的数组,用来保存所有 事件模块的配置结构体指针
7. 解析 events 块中的指令
pcf = *cf;
保存当前配置上下文 cf 的完整状态到 pcf(备份)。
cf->ctx = ctx;
cf->module_type = NGX_EVENT_MODULE;
cf->cmd_type = NGX_EVENT_CONF;
修改 cf 的上下文,使其:ctx 指向刚创建的事件模块配置数组(ctx)。module_type 设为 NGX_EVENT_MODULE,表示当前在解析事件模块。cmd_type 设为 NGX_EVENT_CONF,表示当前指令应匹配 NGX_EVENT_CONF 类型的命令。
rv = ngx_conf_parse(cf, NULL);
调用 Nginx 的通用配置解析器 ngx_conf_parse,递归解析 events 块内部的内容。NULL 表示从当前配置文件当前位置开始解析,直到遇到 }。
*cf = pcf;
恢复原始的配置上下文(避免污染外层解析状态)
if (rv != NGX_CONF_OK) {
return rv;
}
如果解析出错,直接返回错误
8.调用各事件模块的 init_conf 回调
for (i = 0; cf->cycle->modules[i]; i++) {
if (cf->cycle->modules[i]->type != NGX_EVENT_MODULE) {
continue;
}
m = cf->cycle->modules[i]->ctx;
if (m->init_conf) {
rv = m->init_conf(cf->cycle,
(*ctx)[cf->cycle->modules[i]->ctx_index]);
if (rv != NGX_CONF_OK) {
return rv;
}
}
}
再次遍历所有事件模块。
如果模块定义了 init_conf 回调,则调用它,传入:cycle:当前 cycle(包含全局状态)。
该模块的配置结构体指针(从 (*ctx)[ctx_index] 取出)。
init_conf 通常用于:
设置默认值(如果用户未配置)。
验证配置合法性(如 worker_connections 不能为 0)。
初始化内部状态。
9. 返回
return NGX_CONF_OK;
}
所有步骤成功,返回 NGX_CONF_OK,让上层函数知道 ngx_events_block 处理成功
ngx_events_block —— 解析 events { ... } 配置块
│
├── 1. 防重复检查
│ └── 若 *(void**)conf 非空 → 返回 "is duplicate"
│
├── 2. 初始化事件模块配置上下文
│ ├── 2.1 计算事件模块总数
│ │ └── ngx_event_max_module = ngx_count_modules(cycle, NGX_EVENT_MODULE)
│ │
│ ├── 2.2 分配配置上下文 ctx(三层指针)
│ │ ├── ctx = ngx_pcalloc(pool, sizeof(void*)) → 存放指向配置数组的指针
│ │ └── *ctx = ngx_pcalloc(pool, ngx_event_max_module * sizeof(void*)) → 配置数组
│ │
│ └── 2.3 将 ctx 保存到主配置
│ └── *(void**)conf = ctx
│
├── 3. 为每个事件模块创建配置结构体
│ └── 遍历所有模块
│ ├── 跳过非 NGX_EVENT_MODULE 类型模块
│ └── 若模块有 create_conf 回调
│ └── 调用 m->create_conf(cycle)
│ └── 结果存入 (*ctx)[module->ctx_index]
│
├── 4. 解析 events 块内部指令
│ ├── 4.1 保存当前配置上下文(pcf = *cf)
│ ├── 4.2 设置 cf 上下文为事件模块模式
│ │ ├── cf->ctx = ctx
│ │ ├── cf->module_type = NGX_EVENT_MODULE
│ │ └── cf->cmd_type = NGX_EVENT_CONF
│ │
│ ├── 4.3 调用 ngx_conf_parse(cf, NULL)
│ │ └── 递归解析 events { ... } 内所有指令
│ │ └── 指令分发至事件模块的 ngx_command_t::set 回调
│ │
│ └── 4.4 恢复原始配置上下文(*cf = pcf)
│
├── 5. 初始化各事件模块配置
│ └── 遍历所有事件模块
│ ├── 跳过非事件模块
│ └── 若模块有 init_conf 回调
│ └── 调用 m->init_conf(cycle, (*ctx)[ctx_index])
│ └── 用于设默认值、校验、初始化
│
└── 6. 返回 NGX_CONF_OK
- ctx 的结构:
ctx是void***,实际使用为:ctx→ 指向配置数组指针(void**)*ctx→ 配置数组(void*[ngx_event_max_module])(*ctx)[i]→ 第 i 个事件模块的配置结构体(如ngx_epoll_conf_t*)
-
模块遍历两次:
- 第一次:创建配置(
create_conf) - 第二次:初始化配置(
init_conf)
- 第一次:创建配置(
-
配置解析上下文切换 是 Nginx 模块化配置的核心机制,确保
events块中的指令只被事件模块处理。
更多推荐
所有评论(0)