支持HW团队,就支付宝领取下面的红包吧! (打开支付宝就能领取!er1OEj73Uj), (打开支付宝收索“516503473”), 你领取消费,HW有奖励。红包使用无条件限制,有条件请注意是不是有病毒。

Login or Sign up | Validate
| Search

博主:初学MPEG

初学MPEG 本博客-采用Python的web框架Django与Mysql数据库,致力于对Python、Django的了解 与研究
Django技术QQ群:XXXXXXX
Python技术QQ群:XXXXXXX

Category

Keywords

本站最新博文

友情链接  

[转]Nginx源码分析(9)-模块化(4)

类别:Nginx 状态:游客可见,可回,自己可关联(良好) 阅读:3557 评论:0 时间:April 6, 2012, 3:44 p.m.
关键字: nginx

 模块的上下文是四个结构体定义的: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) {
                /* fatal */
                exit(1);
            }
        }
    }

    ...
}

ngx_conf_parse
{
    ...
    ngx_conf_handler
    ...
}

ngx_conf_handler
{
    ...

    // 处理模块的指令集
    for (i = 0; ngx_modules[i]; i++) {

        /* look up the directive in the appropriate modules */

        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 ( /* void */ ; cmd->name.len; cmd++) {

            if (name->len != cmd->name.len) {
                continue;
            }

            if (ngx_strcmp(name->data, cmd->name.data) != 0) {
                continue;
            }


            /* is the directive's location right ? */

            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;
            }

            /* is the directive's argument count right ? */

            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;
                }
            }

            /* set up the directive's configuration context */

            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) {
                /* fatal */
                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的钩子上的操作中调度了这些独特的模块上下文的钩子。

操作:

Please Login (or Sign Up) to leave a comment