Nginx事件管理之核心模块ngx_events_module

Posted 季末的天堂

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Nginx事件管理之核心模块ngx_events_module相关的知识,希望对你有一定的参考价值。

1. ngx_events_module核心模块的功能介绍

ngx_events_module 模式是一个核心模块,它的功能如下:

  • 定义新的事件类型
  • 定义每个事件模块都需要实现的ngx_event_module_t接口
  • 管理这些事件模块生成的配置项结构体,并解析事件类配置项,同时,在解析配置项时会调用其在ngx_command_t数组中定义的配置项结构体.

2. ngx_events_module的框架实现

2.1 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{} 配置项。

2.2 核心模块的通用接口

static ngx_core_module_t  ngx_events_module_ctx = {
    ngx_string("events"),
    NULL,
    ngx_event_init_conf
};

这里,ngx_events_module_ctx 只是实现了init_conf方法,而没有实现create_conf方法,这是因为ngx_events_module模块
并不会解析配置项的参数,只是在出现 "events" 配置项后会调用各事件模块去解析 events{} 块内的配置项。init_conf方
法仅是检测是否能获取到ngx_events_module模块的保存在cycle->conf_ctx数组中的配置项结构体,该结构体保存着所有事件
模块的配置项。

static char *ngx_event_init_conf(ngx_cycle_t *cycle, void *conf)
{
    if (ngx_get_conf(cycle->conf_ctx, ngx_events_module) == NULL) {
        ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
                      "no \\"events\\" section in configuration");
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}

2.3 模块的定义

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
};

从这可以看出,ngx_events_module模块除了对 events 配置项的解析外,没有做其他任何事情。

3. ngx_events_module的配置项管理

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

每一个事件模块都必须实现ngx_event_module_t接口,这个接口中允许每个事件模块建立自己的配置项结构体,用于存储自己
感兴趣的配置项在nginx.conf中对应的参数。ngx_event_module_t 中的 create_conf 方法就是用于创建这个结构体的方法,
事件模块只需要在这个方法中分配内存即可。

每一个事件模块产生的配置结构体指针都会被放到 ngx_events_module 模块创建的指针数组中。而 ngx_cycle_t 核心结构体
中的 conf_ctx 成员,它指向一个指针数组,这个指针数组中就依次存放着所有的 Nginx 模块关于配置项方面的指针。因
此,核心模块 ngx_events_module 管理所有事件模块的总配置项结构体就按 ngx_events_module 模块在全部 Nginx 模块中
的排序号放入到 ngx_cycle_t 核心结构体的成员 conf_ctx 指针数组中的对应下标处。

ngx_cycle_t 结构体中 conf_ctx 的结构示意图

3.2 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 */

    /* 计算出编译进 Nginx 的所有事件模块的总个数 */
    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;
    }

    /* conf 其实就是核心模块 ngx_events_module 在 ngx_cycle_t 核心结构体的成员 conf_ctx 指针数组
     * 相应位置的指针 */
    *(void **) conf = ctx;

    /* 调用所有事件模块的 create_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->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;

    /* 开始解析 events{} 配置块 */
    rv = ngx_conf_parse(cf, NULL);

    *cf = pcf;

    if (rv != NGX_CONF_OK) {
        return rv;
    }

    /* 解析配置项完成后,调用各事件模块的 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;
            }
        }
    }

    return NGX_CONF_OK;
}

以上是关于Nginx事件管理之核心模块ngx_events_module的主要内容,如果未能解决你的问题,请参考以下文章

backbone之事件管理

详解高性能服务框架 Nginx

nginx学习笔记五(nginx的事件模块定义)

Nginx服务器的整体架构

Nginx核心模块ngx_events_module

Nginx 模块自主开发六:源码剖析配置文件解析过程