模块的上下文是四个结构体定义的:ngx_core_module_t、ngx_event_module_t、ngx_http_module_t、ngx_mail_module_t,分别对应于四类模块。
typedef struct {
ngx_str_t name;
void *(*create_conf)(ngx_cycle_t *cycle);
char *(*init_conf)(ngx_cycle_t *cycle, void *conf);
} ngx_core_module_t;(见src/core/ngx_conf_file.h)
typedef struct {
ngx_int_t (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
ngx_int_t (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
ngx_int_t (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
ngx_int_t (*disable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
ngx_int_t (*add_conn)(ngx_connection_t *c);
ngx_int_t (*del_conn)(ngx_connection_t *c, ngx_uint_t flags);
ngx_int_t (*process_changes)(ngx_cycle_t *cycle, ngx_uint_t nowait);
ngx_int_t (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer,
ngx_uint_t flags);
ngx_int_t (*init)(ngx_cycle_t *cycle, ngx_msec_t timer);
void (*done)(ngx_cycle_t *cycle);
} ngx_event_actions_t;
typedef struct {
ngx_str_t *name;
void *(*create_conf)(ngx_cycle_t *cycle);
char *(*init_conf)(ngx_cycle_t *cycle, void *conf);
ngx_event_actions_t actions;
} ngx_event_module_t;(见src/event/ngx_event.h)
typedef struct {
ngx_int_t (*preconfiguration)(ngx_conf_t *cf);
ngx_int_t (*postconfiguration)(ngx_conf_t *cf);
void *(*create_main_conf)(ngx_conf_t *cf);
char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
void *(*create_srv_conf)(ngx_conf_t *cf);
char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
void *(*create_loc_conf)(ngx_conf_t *cf);
char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
} ngx_http_module_t;(见src/http/ngx_http_config.h)
typedef struct {
ngx_mail_protocol_t *protocol;
void *(*create_main_conf)(ngx_conf_t *cf);
char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
void *(*create_srv_conf)(ngx_conf_t *cf);
char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev,
void *conf);
} ngx_mail_module_t;(见src/mail/ngx_mail.h)
这四个结构体都提供了钩子供模块注册与上下文有关的操作,核心模块提供了create_conf和init_conf两个钩子;event模块也提供了 create_conf和init_conf两个钩子,除此之外还提供了一集操作事件的钩子;http模块提供了几个在读取配置文件前后和操作 mail/srv/loc配置项时候执行的钩子;mail模块也提供一些类似于http模块的钩子,不过比http模块简单一些。
只要设置了钩子,这些钩子就会在特定的时机被正确调用,只不过模块的种类不同,其钩子调用的时机也就大不同,这是由于nginx的四种模块之间的差别很大:核心类模块一般是全局性的模块,它们会在系统的许多部分被使用,比如errlog模块负责写错误日志,它被使用在许多地方;event类模块是事件驱动相关的模块,nginx在不同操作系统上都会有结合该操作系统特有接口的事件处理模块,比如在linux中可以使用epoll模块,在freebsd中可以使用 kqueue模块,在solaris中可以使用devpoll事件等;http类模块是用于处理http输入,产生输出,过滤输出,负载均衡等的模块,这是nginx作为web服务器的核心部分,Emiller的论文就是关于http模块的开发指引;mail类模块是实现邮件代理的模块,实现了 smtp/pop3/imap等协议的邮件代理。
到这里,已经把nginx拆开为一个个的模块,后面的分析就可以对每个模块进行详细的剖析,也就可以进入阅读源码的精读阶段了。在这之前,再尝试把这些独立的模块串一下,从main开始,看看nginx是何时在何地调度这些模块干活的。
main
{
...
// 所有模块点一下数
ngx_max_module = 0;
for (i = 0; ngx_modules[i]; i++) {
ngx_modules[i]->index = ngx_max_module++;
}
// 主要的初始化过程,全局的数据存放到ngx_cycle_t结构的变量中
cycle = ngx_init_cycle(&init_cycle);
...
// 启动进程干活
if (ngx_process == NGX_PROCESS_SINGLE) {
ngx_single_process_cycle(cycle);
} else {
ngx_master_process_cycle(cycle);
}
return 0;
}
ngx_init_cycle
{
...
// 调度core模块的钩子create_conf,并且把创建的配置结构体变量存放到cyclep->conf_ctx中
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_conf_parse
...
// 调度core模块的钩子init_conf,设置刚才创建的配置结构体变量(用从配置文件中读取的数据赋值)
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)
{
ngx_destroy_cycle_pools(&conf);
return NULL;
}
}
}
...
// 调度所有模块的init_module钩子,初始化模块
for (i = 0; ngx_modules[i]; i++) {
if (ngx_modules[i]->init_module) {
if (ngx_modules[i]->init_module(cycle) != NGX_OK) {
exit(1);
}
}
}
...
}
ngx_conf_parse
{
...
ngx_conf_handler
...
}
ngx_conf_handler
{
...
// 处理模块的指令集
for (i = 0; ngx_modules[i]; i++) {
if (ngx_modules[i]->type != NGX_CONF_MODULE
&& ngx_modules[i]->type != cf->module_type)
{
continue;
}
cmd = ngx_modules[i]->commands;
if (cmd == NULL) {
continue;
}
for ( ; cmd->name.len; cmd++) {
if (name->len != cmd->name.len) {
continue;
}
if (ngx_strcmp(name->data, cmd->name.data) != 0) {
continue;
}
if (!(cmd->type & cf->cmd_type)) {
if (cmd->type & NGX_CONF_MULTI) {
multi = 1;
continue;
}
goto not_allowed;
}
if (!(cmd->type & NGX_CONF_BLOCK) && last != NGX_OK) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"directive \"%s\" is not terminated by \";\"",
name->data);
return NGX_ERROR;
}
if ((cmd->type & NGX_CONF_BLOCK) && last != NGX_CONF_BLOCK_START) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"directive \"%s\" has no opening \"{\"",
name->data);
return NGX_ERROR;
}
if (!(cmd->type & NGX_CONF_ANY)) {
if (cmd->type & NGX_CONF_FLAG) {
if (cf->args->nelts != 2) {
goto invalid;
}
} else if (cmd->type & NGX_CONF_1MORE) {
if (cf->args->nelts < 2) {
goto invalid;
}
} else if (cmd->type & NGX_CONF_2MORE) {
if (cf->args->nelts < 3) {
goto invalid;
}
} else if (cf->args->nelts > NGX_CONF_MAX_ARGS) {
goto invalid;
} else if (!(cmd->type & argument_number[cf->args->nelts - 1]))
{
goto invalid;
}
}
conf = NULL;
if (cmd->type & NGX_DIRECT_CONF) {
conf = ((void **) cf->ctx)[ngx_modules[i]->index];
} else if (cmd->type & NGX_MAIN_CONF) {
conf = &(((void **) cf->ctx)[ngx_modules[i]->index]);
} else if (cf->ctx) {
confp = *(void **) ((char *) cf->ctx + cmd->conf);
if (confp) {
conf = confp[ngx_modules[i]->ctx_index];
}
}
// 调度指令的钩子set
rv = cmd->set(cf, cmd, conf);
if (rv == NGX_CONF_OK) {
return NGX_OK;
}
if (rv == NGX_CONF_ERROR) {
return NGX_ERROR;
}
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"%s\" directive %s", name->data, rv);
return NGX_ERROR;
}
}
...
}
ngx_master_process_cycle
{
...
ngx_start_worker_processes
...
ngx_master_process_exit
...
}
ngx_start_worker_processes
{
...
// for i = 0 to n
ngx_worker_process_cycle
...
}
ngx_worker_process_cycle
{
...
ngx_worker_process_init
...
ngx_worker_process_exit
...
}
ngx_worker_process_init
{
...
// 调度所有模块的钩子init_process
for (i = 0; ngx_modules[i]; i++) {
if (ngx_modules[i]->init_process) {
if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) {
exit(2);
}
}
}
...
}
ngx_worker_process_exit
{
...
// 调度所有模块的钩子exit_process
for (i = 0; ngx_modules[i]; i++) {
if (ngx_modules[i]->exit_process) {
ngx_modules[i]->exit_process(cycle);
}
}
...
}
ngx_master_process_exit
{
...
// 调度所有模块的钩子exit_master
for (i = 0; ngx_modules[i]; i++) {
if (ngx_modules[i]->exit_master) {
ngx_modules[i]->exit_master(cycle);
}
}
...
}
在这个调度流中,我们并没有看到event类模块、http类模块和mail类模块钩子的调度,那是由于这三类模块注册到ngx_module_t的钩子和ngx_command_t的钩子上的操作中调度了这些独特的模块上下文的钩子。
阅读(1651) | 评论(0) | 转发(0) |