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 块)。

注意:confvoid** 类型,*(void**)confvoid*,用于存放 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 中。
这个值用于后续分配数组空间(每个事件模块一个配置指针)。


ngx_count_modules


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 的结构ctxvoid***,实际使用为:
    • ctx → 指向配置数组指针(void**
    • *ctx → 配置数组(void*[ngx_event_max_module]
    • (*ctx)[i] → 第 i 个事件模块的配置结构体(如 ngx_epoll_conf_t*

  • 模块遍历两次

    • 第一次:创建配置(create_conf
    • 第二次:初始化配置(init_conf
  • 配置解析上下文切换 是 Nginx 模块化配置的核心机制,确保 events 块中的指令只被事件模块处理。


Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐