9.4.2 管理事件模块
上文说到,配置项结构体指针的保存都是在ngx_events_block方法中进行的。下面再来看一下这个方法执行的流程图,如图9-3所示。
图 9-3 ngx_events_module核心模块如何加载事件模块
下面简要描述一下这5个步骤。
1)首先初始化所有事件模块的ctx_index成员。这里要先回顾一下ngx_module_t模块接口的定义,如下所示。
struct ngx_module_s{
ngx_uint_t ctx_index;
ngx_uint_t index;
……
}
这里的index是所有模块在ngx_modules.c文件的ngx_modules数组中的序号,它与ngx_modules数组中所有模块的顺序是一致的。什么时候初始化这个index呢?启动Nginx后,在调用第8章中介绍过的ngx_init_cycle方法前就会进行,代码如下。
ngx_max_module=0;
for(i=0;ngx_modules[i];i++){
ngx_modules[i]->index=ngx_max_module++;
}
其中,ngx_max_module是Nginx模块的总个数。注意,本书前文曾多次提到过,Nginx各模块在ngx_modules数组中的顺序是很重要的,依靠index成员,每一个模块才可以把自己的位置与其他模块的位置进行比较,并以此决定行为。但是,Nginx同时又允许再次定义子类型,如事件类型、HTTP类型、mail类型,那同一类型的模块间又如何区分顺序呢(依靠index当然可以区分顺序,但index是针对所有模块的,这样效率太差)?这就得依靠ctx_index成员了。ctx_index表明了模块在相同类型模块中的顺序。
因此,ngx_events_block方法的第一步就是初始化所有事件模块的ctx_index成员,这会决定以后加载各事件模块的顺序。其代码非常简单,如下所示。
ngx_event_max_module=0;
for(i=0;ngx_modules[i];i++){
if(ngx_modules[i]->type!=NGX_EVENT_MODULE){
continue;
}
ngx_modules[i]->ctx_index=ngx_event_max_module++;
}
其中,ngx_event_max_module是编译进Nginx的所有事件模块的总个数。
2)分配9.4.1节中介绍的指针数组,不再详述。
3)依次调用所有事件模块通用接口ngx_event_module_t中的create_conf方法,当然,产生的结构体的指针保存在上面的指针数组中。
4)针对所有事件类型的模块解析配置项。这时,每个事件模块定义的ngx_command_t决定了配置项的解析方法,如果在nginx.conf中发现相应的配置项,就会回调各事件模块定义的方法。
5)解析完配置项后,依次调用所有事件模块通用接口ngx_event_module_t中的init_conf方法,实现了这个方法的事件模块可以在此做一些配置参数的整合工作。
以上就是ngx_events_module模块的核心工作流程。对于事件驱动机制,更多的工作是在ngx_event_core_module模块中进行的,下面继续看一下这个模块做了些什么。