前言
本小节将进入到ngx_event_core_module
模块,它是所有事件模块中排第一位的模块,因为要负责创建连接池,还要选择I/O多路复用机制等工作。接下来我们就来看看它是如何做到的,以及在nginx中扮演了一个什么角色。
模块的通用接口
我们先来看看ngx_event_core_module
模块实现的所有模块都需要实现的ngx_module_t
接口。
ngx_module_t ngx_event_core_module = {
/* NGX_MODULE_V1定义为:
* #define NGX_MODULE_V1 0, 0, 0, 0, 0, 0, 1
* 直接初始化前7个成员
*/
NGX_MODULE_V1,
/* ctx成员,事件模块的具体化接口 */
&ngx_event_core_module_ctx, /* module context */
//ngx_command_t成员
ngx_event_core_commands, /* module directives */
//模块类型
NGX_EVENT_MODULE, /* module type */
NULL, /* init master */
//初始化ngx_event_core_module模块
ngx_event_module_init, /* init module */
//在进入到工作循环前进行初始化
ngx_event_process_init, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
/* 将预留空间填充为0 */
NGX_MODULE_V1_PADDING
};
关于ngx_event_module_init
方法,在进入到master进程工作循环前由ngx_init_cycle
调用:
//调用所有模块的init_module方法
for (i = 0; ngx_modules[i]; i++) {
if (ngx_modules[i]->init_module) {
if (ngx_modules[i]->init_module(cycle) != NGX_OK) {
/* fatal */
exit(1);
}
}
}
ngx_event_module_init
所做的工作主要是初始化了一些变量,这里不具体分析(因为跟一些用于统计的变量有关,与该模块的联系不是特别大)
关于ngx_event_process_init
,其实上一小节我们已经分析了它是如何创建连接池、读事件、写事件,不过除此之外,它还做了其他事情,比如调用指定的I/O多路复用机制模块的init方法。
关于它的调用,它是在ngx_worker_process_init
中被调用。从main
函数开始的调用栈如图:
而其的源码如下:
static ngx_int_t
ngx_event_process_init(ngx_cycle_t *cycle)
{
ngx_uint_t m, i;
ngx_event_t *rev, *wev;
ngx_listening_t *ls;
ngx_connection_t *c, *next, *old;
ngx_core_conf_t *ccf;
ngx_event_conf_t *ecf;
ngx_event_module_t *module;
//获取ngx_core_module的配置项结构体指针
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
//获取ngx_event_core_module的配置项结构体指针
ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
/* 当配置文件中的负载均衡锁的选项启用
* 并且使用的是多进程模型(worker进程数大于1并且使用了master进程)
* 于是开启accept_mutex负载均衡锁(代表需要进行负载均衡)
*/
if (ccf->master && ccf->worker_processes > 1 && ecf->accept_mutex) {
//将全局负载均衡锁开关置为1
ngx_use_accept_mutex = 1;
//ngx_accept_mutex_held为0代表表示当前进程未获取到负载均衡锁
//为1代表获取到了
ngx_accept_mutex_held = 0;
//ngx_accept_mutex_delay的值为在配置文件中指定的最大延迟时间
//具体所代表的含义,我们在后面分析进程间负载均衡的时候再去了解
ngx_accept_mutex_delay = ecf->accept_mutex_delay;
} else {
//否则将该全局变量置为0
//表示不启用负载均衡(毕竟只有一个进程)
ngx_use_accept_mutex = 0;
}
#if (NGX_THREADS)
ngx_posted_events_mutex = ngx_mutex_init(cycle->log, 0);
if (ngx_posted_events_mutex == NULL) {
return NGX_ERROR;
}
#endif
//初始化定时器(nginx中的定时器是由红黑树实现的)
if (ngx_event_timer_init(cycle->log) == NGX_ERROR) {
return NGX_ERROR;
}
//遍历所有事件模块
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_EVENT_MODULE) {
continue;
}
//配置项中的use选项选择了使用的I/O多路复用机制
//找到事件模块中的该事件驱动模块
if (ngx_modules[m]->ctx_index != ecf->use) {
continue;
}
module = ngx_modules[m]->ctx;
//调用该模块对应的init方法进行初始化
if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) {
/* fatal */
exit(2);
}
break;
}
#if !(NGX_WIN32)
/* nginx中采用了时间缓存,并不是需要获取时间时就调用gettimeofday来获取
* 因此精度方面可能需要进行控制
* 而ngx_timer_resolution(通过核心模块的配置项获取,默认是0)表示时间的精度
* 而NGX_USE_TIMER_EVENT在epoll中并没有使用
* 因此只要设置了控制时间的精度
* 就会定期进行更新
*/
if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) {
/* 设置SIGALRM捕捉之后的处理函数
* ngx_timer_signal_handler