加载中…
个人资料
DreamHunter
DreamHunter
  • 博客等级:
  • 博客积分:0
  • 博客访问:15,679
  • 关注人气:6
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
谁看过这篇博文
加载中…
正文 字体大小:

Nginx源码学习,配置文件的加载与初始化

(2012-07-20 15:03:24)
标签:

nginx

学习笔记

it

分类: 高性能服务器

@踩在巨人的肩膀上。2011-11-04

 

配置文件的加载过程都是在main函数调用ngx_init_cycle完成的。

 

cycle是整个进程持有的配置结构,首先在cycle为每个模块分配指向各自conf的指针空间,conf_ctx维护一个指针数组,以后按照模块的index编号访问对应的conf

    //分配ngx_max_module个指针,这些指针将来都指向对应块的conf结构

    cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));

    if (cycle->conf_ctx == NULL) {

        ngx_destroy_pool(pool);

        return NULL;

    }

 

因为不同模块有不同的conf结构,依次调用各自create_conf钩子函数,为cycle->conf_ctx[]中分配对应的空间。这些数据都分配在cyclepool中。具体的钩子函数实现可以参考ngx_core_module_create_conf,其中无非是在poolpalloc一个空间存放conf.

      //遍历数据core的模块,调用create_conf钩子函数,

    //建立不同模块对应的配置结构体rv,并将该模块的conf_ctx指向该rv

    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;

        }

    }

 

给各自的conf分配完内存空间,接下来就是去解析配置文件。

首先为解析配置文件的准备工作,创建一个临时的ngx_conf_t conf,保存了cycle/conf_ctx/pool等信息。最主要的是将conf.ctx指向cycle->conf_ctx

    conf.ctx = cycle->conf_ctx;

    conf.cycle = cycle;

    conf.pool = pool;

    conf.log = log;

    conf.module_type = NGX_CORE_MODULE;

    conf.cmd_type = NGX_MAIN_CONF;

 

接下来开始解析配置文件,在ngx_conf_parsenginx会读取配置文件,读取到一个属性或是一个块block,会调用cmd中的set钩子函数,该钩子实现了对特定属性或block提取,并填充到模块对应的conf中。具体的文件解析过程很复杂,以后有机会可以研读一下。

    //读取配置文件,保存在conf结构中

    if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {

        environ = senv;

        ngx_destroy_cycle_pools(&conf);

        return NULL;

    }

 

ngx_conf_parse中只会调用核心模块的cmdset回调,核心模块暂时只有四个:ngx_core_modulengx_errlog_modulengx_events_modulengx_http_module

比如http模块,http核心模块set钩子函数为ngx_http_block

进入到ngx_http_block函数里后,http核心模块没有create_con等钩子,分配conf空间的工作也都在这个set钩子中实现。

typedef struct {//http有如下三类配置类型

    void        **main_conf;

    void        **srv_conf;

    void        **loc_conf;

} ngx_http_conf_ctx_t;

分配如上内存到ctx,并给各HTTP模块计数ctx_index,将来会依靠这个ctx_index访问对应的conf.

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

    }

并根据http类型模块数,维护三个指向conf的指针数组:main_conf,srv_conf,loc_conf

    ctx->main_conf = ngx_pcalloc(cf->pool,

                                 sizeof(void *) * ngx_http_max_module);

    if (ctx->main_conf == NULL) {

        return NGX_CONF_ERROR;

}

….

然后遍历所有HTTP模块,调用各自的create conf的钩子,其中这些钩子,就是独立开发模块需要实现的内容。

    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;

            }

        }

    }

http block中调用ngx_conf_parse,也就是会调用到子模块的set钩子

注意的是在调用ngx_conf_parse前,已经将参数cf直接指向了ctx,

    cf->ctx = ctx;   

 cf->module_type = NGX_HTTP_MODULE;//更改标志,这样就能调用到http子模块的set

cf->cmd_type = NGX_HTTP_MAIN_CONF;

rv = ngx_conf_parse(cf, NULL);

之后跳出再执行一些子模块的init conf的钩子

 

 

再之后就是回归到核心模块

执行完所有模块的set钩后,最后是各模块调用init_conf的钩子函数完成最后的初始化工作。

    //初始化各个模块的配置信息,就是按照自己的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)

            {

                environ = senv;

                ngx_destroy_cycle_pools(&conf);

                return NULL;

            }

        }

    }

 

 

二、配置的访问

核心模块的conf都保存在cycle->conf_ctx中,然后根据模块的Index,轻松就可以直接访问到。

其中:

    #define ngx_get_conf(conf_ctx, module)  conf_ctx[module.index]

    //获取core模块配置信息

    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);

 

子模块,比如http子模块获取配置分为三类,main,srv,loc

需要提前获取HTTP CORE模块的ctx才行。

#define ngx_http_cycle_get_module_main_conf(cycle, module)                    \

    (cycle->conf_ctx[ngx_http_module.index] ?                                 \

        ((ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index])      \

            ->main_conf[module.ctx_index]:                                    \

        NULL)

 

 

 

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有