1.ngx_modules数组的产生 ngx_modules数组是在执行configure脚本后自动生成的,在objs/ngx_modules.c文件中。该数组即当前编译版本中的所有Nginx模块。 做如下操作,可以看到ngx_moduels数组的一般形式: 1.1 最简单的Nginx框架,不包含任何HTTP模块 cd nginx-1.6.2 ./configure --without-http 此时,objs/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; ngx_module_t *ngx_modules[] = { &ngx_core_module, &ngx_errlog_module, &ngx_conf_module, &ngx_events_module, &ngx_event_core_module, &ngx_epoll_module, NULL }; 1.2 默认的ngx_modules数组: make clean cd nginx-1.6.2 ./configure 此时,objs/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_regex_module; extern ngx_module_t ngx_http_module; extern ngx_module_t ngx_http_core_module; extern ngx_module_t ngx_http_log_module; extern ngx_module_t ngx_http_upstream_module; extern ngx_module_t ngx_http_static_module; extern ngx_module_t ngx_http_autoindex_module; extern ngx_module_t ngx_http_index_module; extern ngx_module_t ngx_http_auth_basic_module; extern ngx_module_t ngx_http_access_module; extern ngx_module_t ngx_http_limit_conn_module; extern ngx_module_t ngx_http_limit_req_module; extern ngx_module_t ngx_http_geo_module; extern ngx_module_t ngx_http_map_module; extern ngx_module_t ngx_http_split_clients_module; extern ngx_module_t ngx_http_referer_module; extern ngx_module_t ngx_http_rewrite_module; extern ngx_module_t ngx_http_proxy_module; extern ngx_module_t ngx_http_fastcgi_module; extern ngx_module_t ngx_http_uwsgi_module; extern ngx_module_t ngx_http_scgi_module; extern ngx_module_t ngx_http_memcached_module; extern ngx_module_t ngx_http_empty_gif_module; extern ngx_module_t ngx_http_browser_module; extern ngx_module_t ngx_http_upstream_ip_hash_module; extern ngx_module_t ngx_http_upstream_least_conn_module; extern ngx_module_t ngx_http_upstream_keepalive_module; extern ngx_module_t ngx_http_write_filter_module; extern ngx_module_t ngx_http_header_filter_module; extern ngx_module_t ngx_http_chunked_filter_module; extern ngx_module_t ngx_http_range_header_filter_module; extern ngx_module_t ngx_http_gzip_filter_module; extern ngx_module_t ngx_http_postpone_filter_module; extern ngx_module_t ngx_http_ssi_filter_module; extern ngx_module_t ngx_http_charset_filter_module; extern ngx_module_t ngx_http_userid_filter_module; extern ngx_module_t ngx_http_headers_filter_module; extern ngx_module_t ngx_http_copy_filter_module; extern ngx_module_t ngx_http_range_body_filter_module; extern ngx_module_t ngx_http_not_modified_filter_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_regex_module, &ngx_http_module, &ngx_http_core_module, &ngx_http_log_module, &ngx_http_upstream_module, &ngx_http_static_module, &ngx_http_autoindex_module, &ngx_http_index_module, &ngx_http_auth_basic_module, &ngx_http_access_module, &ngx_http_limit_conn_module, &ngx_http_limit_req_module, &ngx_http_geo_module, &ngx_http_map_module, &ngx_http_split_clients_module, &ngx_http_referer_module, &ngx_http_rewrite_module, &ngx_http_proxy_module, &ngx_http_fastcgi_module, &ngx_http_uwsgi_module, &ngx_http_scgi_module, &ngx_http_memcached_module, &ngx_http_empty_gif_module, &ngx_http_browser_module, &ngx_http_upstream_ip_hash_module, &ngx_http_upstream_least_conn_module, &ngx_http_upstream_keepalive_module, &ngx_http_write_filter_module, &ngx_http_header_filter_module, &ngx_http_chunked_filter_module, &ngx_http_range_header_filter_module, &ngx_http_gzip_filter_module, &ngx_http_postpone_filter_module, &ngx_http_ssi_filter_module, &ngx_http_charset_filter_module, &ngx_http_userid_filter_module, &ngx_http_headers_filter_module, &ngx_http_copy_filter_module, &ngx_http_range_body_filter_module, &ngx_http_not_modified_filter_module, NULL }; 2.直接使用ngx_modules的场景 如上所述,ngx_modules数组代表了当前Nginx中的所有模块,由于每一个Nginx模块,即ngx_module_t类型的变量,其ctx变量一般为如下几个类型之一: ngx_core_module_t ngx_event_module_t ngx_http_module_t ngx_mail_module_t 所以,可以对所有的Nginx模块按其ctx类型进行分类,当然并不是所有的nginx模块都有ctx成员,例如ngx_conf_module模块的ctx成员为NULL,但可以认为绝大部分模块都属于上述四类模块之一。 每一类模块下的所有模块,由于其ctx结构是一样的,因而在程序执行逻辑上会有共同点。具体来说,我们可以遍历ngx_modules数组成员,判断其属于上述四类的哪一类模块,再调用其对应的ctx成员中的函数指针,这样就会屏蔽掉具体的模块名称,抽象到框架的层面上。 那么,如何判断一个模块属于上述四类模块中的哪一类呢?这就是模块变量的type成员的作用了。 所有的ngx_core_module_t类型的模块,其type成员为NGX_CORE_MODULE 所有的ngx_event_module_t类型的模块,其type成员为NGX_EVENT_MODULE 所有的ngx_http_module_t类型的模块,其type成员为NGX_HTTP_MODULE 所有的ngx_mail_module_t类型的模块,其type成员为NGX_MAIL_MODULE 所以,在遍历ngx_modules数组时,即可根据每一个数组成员的type成员,来判断该模块属于哪种类型的模块,进而执行该模块对应的钩子函数。 下面,我们以nginx-1.6.2为例,看看程序在哪些地方对nginx_modules数组进行了遍历。 2.1 统计模块数量 ngx_max_module = 0; for (i = 0; ngx_modules[i]; i++) { ngx_modules[i]->index = ngx_max_module++; } 上述代码在nginx.c的main函数中,可以看到,其作用为: 统计系统中到底有多少个模块,记录在全局变量ngx_max_module中。 将每个模块在ngx_modules数组中的序号,记录在模块的index变量中。 2.2 用来解析每个模块的配置 具体见函数ngx_conf_handler。 2.3 执行每个模块的ctx中的钩子函数 例如,ngx_init_cycle函数中: for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_CORE_MODULE) { continue; } module = ngx_modules[i]->ctx; if (module->create_conf) { rv = module->create_conf(cycle); if (rv == NULL) { ngx_destroy_pool(pool); return NULL; } cycle->conf_ctx[ngx_modules[i]->index] = rv; } } 以上代码对所有的ngx_core_module_t类型的模块,调用其ctx成员中的create_conf钩子函数。 2.4 同样在在ngx_init_cycle函数: for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_CORE_MODULE) { continue; } module = ngx_modules[i]->ctx; if (module->init_conf) { if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index]) == NGX_CONF_ERROR) { environ = senv; ngx_destroy_cycle_pools(&conf); return NULL; } } } 以上代码对所有的ngx_core_module_t类型的模块,调用其ctx成员的init_conf钩子函数。 2.5 继续看ngx_init_cycle函数: 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); } } } 以上代码调用所有的nginx模块(ngx_module_t变量)的init_module钩子函数(如果不为空的话)。 2.6 在ngx_event_process_init函数中: for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_EVENT_MODULE) { continue; } if (ngx_modules[m]->ctx_index != ecf->use) { continue; } module = ngx_modules[m]->ctx; if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) { /* fatal */ exit(2); } break; } 调用event模块的ctx成员中的actions.init钩子函数,对于epoll,则是ngx_epoll_init函数。 2.7 在ngx_events_block函数中: 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_MODULE类型的模块,初始化其ctx_index变量。主要有两点: ngx_event_max_module代表了ngx_event_module_t类型模块的个数。而ngx_max_module则代表了所有模块的个数。 ctx_index成员表示该模块在该类模块(本例中为ngx_event_module_t类型的模块)中的序号。 2.8 在ngx_events_block函数中: for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_EVENT_MODULE) { continue; } m = ngx_modules[i]->ctx; if (m->create_conf) { (*ctx)[ngx_modules[i]->ctx_index] = m->create_conf(cf->cycle); if ((*ctx)[ngx_modules[i]->ctx_index] == NULL) { return NGX_CONF_ERROR; } } } 上面的代码,对于所有的NGX_EVENT_MODULE类型的模块,调用其ctx成员中的create_conf钩子函数。 2.9 在ngx_events_block函数中: for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_EVENT_MODULE) { continue; } m = ngx_modules[i]->ctx; if (m->init_conf) { rv = m->init_conf(cf->cycle, (*ctx)[ngx_modules[i]->ctx_index]); if (rv != NGX_CONF_OK) { return rv; } } } 上面的代码,对于所有的NGX_EVENT_MODULE类型的模块,调用其ctx成员中的init_conf钩子函数。 2.10 在ngx_event_use函数中: for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_EVENT_MODULE) { continue; } module = ngx_modules[m]->ctx; if (module->name->len == value[1].len) { if (ngx_strcmp(module->name->data, value[1].data) == 0) { ecf->use = ngx_modules[m]->ctx_index; ecf->name = module->name->data; if (ngx_process == NGX_PROCESS_SINGLE && old_ecf && old_ecf->use != ecf->use) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "when the server runs without a master process " "the \"%V\" event type must be the same as " "in previous configuration - \"%s\" " "and it cannot be changed on the fly, " "to change it you need to stop server " "and start it again", &value[1], old_ecf->name); return NGX_CONF_ERROR; } return NGX_CONF_OK; } } } ngx_event_use是ngx_event_core_module模块的指令"use"的解析函数。 2.11 在函数ngx_http_block中: ngx_http_max_module = 0; for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_HTTP_MODULE) { continue; } ngx_modules[m]->ctx_index = ngx_http_max_module++; } 上面的代码主要做了两件事情: 遍历所有的ngx_http_module_t类型的模块,统计这种模块的个数,存在变量ngx_http_max_module中。 初始化每个ngx_http_module_t类型的模块的ctx_index变量,该值的涵义是每个ngx_http_module_t模块在所有该类模块中的序号。 2.12 在函数ngx_http_block中: for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_HTTP_MODULE) { continue; } module = ngx_modules[m]->ctx; mi = ngx_modules[m]->ctx_index; if (module->create_main_conf) { ctx->main_conf[mi] = module->create_main_conf(cf); if (ctx->main_conf[mi] == NULL) { return NGX_CONF_ERROR; } } if (module->create_srv_conf) { ctx->srv_conf[mi] = module->create_srv_conf(cf); if (ctx->srv_conf[mi] == NULL) { return NGX_CONF_ERROR; } } if (module->create_loc_conf) { ctx->loc_conf[mi] = module->create_loc_conf(cf); if (ctx->loc_conf[mi] == NULL) { return NGX_CONF_ERROR; } } } 上面的代码分别调用所有ngx_http_module_t类型模块的create_main_conf、create_srv_conf和create_loc_conf钩子函数。 2.13 同样在ngx_http_block函数中: for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_HTTP_MODULE) { continue; } module = ngx_modules[m]->ctx; if (module->preconfiguration) { if (module->preconfiguration(cf) != NGX_OK) { return NGX_CONF_ERROR; } } } 调用所有ngx_http_module_t类型模块的preconfiguration钩子函数。 2.14 同样在ngx_http_block函数中: for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_HTTP_MODULE) { continue; } module = ngx_modules[m]->ctx; mi = ngx_modules[m]->ctx_index; /* init http{} main_conf's */ if (module->init_main_conf) { rv = module->init_main_conf(cf, ctx->main_conf[mi]); if (rv != NGX_CONF_OK) { goto failed; } } rv = ngx_http_merge_servers(cf, cmcf, module, mi); if (rv != NGX_CONF_OK) { goto failed; } } 上面的代码首先调用所有ngx_http_module_t类型模块的init_main_conf钩子函数,然后对main, server, location等配置进行了合并。 2.15 仍然看ngx_http_block函数: for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_HTTP_MODULE) { continue; } module = ngx_modules[m]->ctx; if (module->postconfiguration) { if (module->postconfiguration(cf) != NGX_OK) { return NGX_CONF_ERROR; } } } 很明显,上面的代码调用了所有ngx_http_module_t类型的模块的postconfiguration钩子函数。 2.16 在函数ngx_mail_block中: ngx_mail_max_module = 0; for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_MAIL_MODULE) { continue; } ngx_modules[m]->ctx_index = ngx_mail_max_module++; } 不难看出,该段代码主要完成两点功能: 统计所有的ngx_mail_module_t类型的模块,存入变量ngx_mail_max_module中。 初始化每个ngx_mail_module_t类型模块的ctx_index变量,该变量表示每个该类变量在所有ngx_mail_module_t变量中的序号。 mail与http类似,还有许多关于ngx_mail_module_t的ctx变量的钩子函数的调用,这里略过。 2.17 在函数ngx_single_process_cycle中: for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->init_process) { if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { /* fatal */ exit(2); } } } 以上代码调用所有模块的init_process钩子函数。 2.18 在函数ngx_master_process_exit中: for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->exit_master) { ngx_modules[i]->exit_master(cycle); } } 以上代码调用所有模块的exit_process钩子函数。 2.19 在函数ngx_worker_process_init函数中: for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->init_process) { if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { /* fatal */ exit(2); } } } 上面的代码调用所有模块的init_process钩子函数. 2.20 在函数ngx_worker_process_exit中: for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->exit_process) { ngx_modules[i]->exit_process(cycle); } } 上面的代码调用了所有模块的exit_process钩子函数。 (责任编辑:IT) |