一、执行configure
./configure 自动脚本根据configure参数自动生成ngx_modules.c,里面包含了所有模块的声明,并把所有模块维护在ngx_modules[]数组里面。
./configure \
--prefix=/usr \
--sbin-path=/usr/sbin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--pid-path=/var/run/nginx/nginx.pid \
--lock-path=/var/lock/nginx.lock \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_flv_module \
--with-http_gzip_static_module \
--without-http_rewrite_module \
--http-log-path=/var/log/nginx/access.log \
--http-client-body-temp-path=/var/tmp/nginx/client/ \
--http-proxy-temp-path=/var/tmp/nginx/proxy/ \
--http-fastcgi-temp-path=/var/tmp/nginx/fcgi/
运行自动脚本生成的ngx_modules.c
#include <ngx_config.h> #include <ngx_core.h> extern ngx_module_t ngx_core_module; extern ngx_module_t ngx_errlog_module; extern ngx_module_t ngx_conf_module; extern ngx_module_t ngx_events_module; extern ngx_module_t ngx_event_core_module; extern ngx_module_t ngx_epoll_module; extern ngx_module_t ngx_openssl_module; 。。。 。。。 ngx_module_t *ngx_modules[] = { &ngx_core_module, //模块列表 &ngx_errlog_module, &ngx_conf_module, &ngx_events_module, &ngx_event_core_module, &ngx_epoll_module, &ngx_openssl_module, 。。。 。。。 NULL }; |
二、初始化模块
nginx.c中main函数中:
ngx_max_module = 0; for (i = 0; ngx_modules[i]; i++) { ngx_modules[i]->index = ngx_max_module++; } |
ngx_max_module记录模块数,每个模块用唯一的index区别。
然后调用ngx_init_cycle,该函数是nginx启动初始化的核心之处,同时模块的配置加载、初始化也在其中完成。
187 cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *)); 188 if (cycle->conf_ctx == NULL) { 189 ngx_destroy_pool(pool); 190 return NULL; 191 } |
首先根据ngx_max_module大小申请一块内存池 ,cycle->conf_ctx在这扮演很重要的角色,我们得知ngx_max_modules统计了模块总数,因此可以看出cycle中的conf_ctx将存储每个module的某些信息。接下来的for循环验证了我们的猜想。
214 for (i = 0; ngx_modules[i]; i++) { 215 if (ngx_modules[i]->type != NGX_CORE_MODULE) { 216 continue; 217 } 219 module = ngx_modules[i]->ctx; 221 if (module->create_conf) { 222 rv = module->create_conf(cycle); 223 if (rv == NULL) { 224 ngx_destroy_pool(pool); 225 return NULL; 226 } 227 cycle->conf_ctx[ngx_modules[i]->index] = rv; 228 } 229 } |
在for循环中,调用NGX_CORE_MODULE类型模块的ceate_conf回调,创建相应的配置结构存储空间,然后将这个配置结构存储空间的地址保存到conf_ctx数组的对应单元处。寻找正确的对应单元就是通过每个模块的index字段。通过对NGX_CORE_MODULE类型模块的处理,我们暂且猜测conf_ctx数组就是用来存储每个模块的配置结构;利用这个数组,我们能够获取每个模块相应的配置数据。
疑惑:conf_ctx指向的是内存池的一块空间,保存着各个模块的相关配置信息,不过它是个 四级指针,这个怎么变成数组来应用了呢?
NGX_CORE_MODULE类型的模块有:ngx_core_module、ngx_errlog_module、ngx_events_module和ngx_http_module等。
ngx_core_module定义在src/core/nginx.c文件中,create_conf钩子对应的函数为ngx_core_module_create_conf(),此函数就是创建ngx_core_conf_t配置结构。
ngx_errlog_module定义在src/core/ngx_log.c中,create_conf钩子没有对应的回调函数,为NULL。
ngx_events_module定义在src/event/ngx_event.c中,create_conf钩子没有对应的回调函数,为NULL。
ngx_http_module定义在src/http/ngx_http.c中,create_conf钩子没有对应的回调函数,为NULL。
由此可以看出,此处的循环执行create_conf回调函数,其实就只调用了ngx_core_module_create_conf()。
261 if (ngx_conf_param(&conf) != NGX_CONF_OK) { 262 environ = senv; 263 ngx_destroy_cycle_pools(&conf); 264 return NULL; 265 } 266 267 if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) { 268 environ = senv; 269 ngx_destroy_cycle_pools(&conf); 270 return NULL; 271 } |
这里将完成对配置文件的解析工作,做过Nginx模块开发的都清楚——解析配置文件的时候,将会完成每个指令的set回调,这个set回调函数一般都是用于将配置数据填写到配置结构中。 解析配置文件常用的手法之一就是利用状态机,但此处Nginx却没有明确的使用状态机来完成配置文件的解析工作。
后经仔细阅读代码,只有配置模块的type符合NGX_CONF_MODULE,会调用set回调。代码在ngx_config_file.c ,如下
292 for (i = 0; ngx_modules[i]; i++) { 293 294 295 296 if (ngx_modules[i]->type != NGX_CONF_MODULE 297 && ngx_modules[i]->type != cf->module_type) 298 { 299 continue; 300 } 302 cmd = ngx_modules[i]->commands; 。 。 。 393 rv = cmd->set(cf, cmd, conf); |
|
其中set回调在定义ngx_conf_commands时赋值为ngx_conf_include,代码见ngx_config_file.c:23。ngx_conf_include函数的作用以后再详细查看。
还有就是核心模块的set回调,见如下代码nginx.c:32
static ngx_command_t ngx_core_commands[] = {
{ ngx_string("daemon"), NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, //set回调函数 0, offsetof(ngx_core_conf_t, daemon), NULL },
{ ngx_string("master_process"), NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, //set回调函数 0, offsetof(ngx_core_conf_t, master), NULL }, . . . } |
以上作用都是将配置信息解析出来,放在提前分配好的内存空间,之后可以随时访问这些配置信息。
278 for (i = 0; ngx_modules[i]; i++) { 279 if (ngx_modules[i]->type != NGX_CORE_MODULE) { 280 continue; 281 } 282 283 module = ngx_modules[i]->ctx; 284 285 if (module->init_conf) { 286 if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index]) 287 == NGX_CONF_ERROR) 288 { 289 environ = senv; 290 ngx_destroy_cycle_pools(&conf); 291 return NULL; 292 } 293 } 294 } |
前面完成了NGX_CORE_MODULE类型模块的配置结构创建工作,这里调用所有NGX_CORE_MODULE类型模块的init_conf回调函数,完成配置结构的初始化工作。同ceate_conf,其实此处也只是调用了ngx_core_module的ngx_core_module_init_conf()回调函数。对ceate_conf创建的配置结构进行初始化。其他几个NGX_CORE_MODULE没有init_conf回调函数。
597 for (i = 0; ngx_modules[i]; i++) { 598 if (ngx_modules[i]->init_module) { 599 if (ngx_modules[i]->init_module(cycle) != NGX_OK) { 600 601 exit(1); 602 } 603 } 604 } |
执行所有模块的init_module操作,看名字为对模块进行初始化。 浏览源码,发现包括几个NGX_CORE_MODULE类型的模块在内的绝大多数模块都没有这个init回调函数。究竟哪些模块才使用这个回调接口呢?动用搜索功能,终于找到了一个模块使用了这个回调接口,它就是ngx_event_core_module。在此,就不纠结这个独特的初始化函数了,到分析事件驱动的时候,再回头看看。
http://blog.sina.com.cn/s/blog_8755c64501011jdf.html
http://www.linuxidc.com/Linux/2011-05/35348.htm
http://www.cnblogs.com/luhouxiang/archive/2012/09/19/2693632.html
http://www.cnblogs.com/luhouxiang/archive/2012/09/18/2690161.html