用户工具

站点工具


about_ngx_2

Nginx源码分析 第二章 配置文件解析过程

1.初始化过程

ngx在main函数执行的时候会调用ngx_init_cycle,在这个过程中,会进行初始化的几个步骤:

1.1 create_conf

针对core_module类型的模块,将会调用create_conf方法:

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

并且把根据模块号存入了cycle→conf_ctx中。

这个过程主要是进行配置数据结构的初始化,以epoll模块为例:

static void *
ngx_epoll_create_conf(ngx_cycle_t *cycle)
{
    ngx_epoll_conf_t  *epcf;
 
    epcf = ngx_palloc(cycle->pool, sizeof(ngx_epoll_conf_t));
    if (epcf == NULL) {
        return NULL;
    }
 
    epcf->events = NGX_CONF_UNSET;
    epcf->aio_requests = NGX_CONF_UNSET;
 
    return epcf;
}

1.2 ngx_conf_parse 解析配置文件

这个函数一共有以下几个过程:

a) ngx_conf_read_token

这个过程主要进行配置配置的解析工作,解析完成的一个配置结构为:

struct ngx_conf_s {
    char                 *name;
    ngx_array_t          *args;

    ngx_cycle_t          *cycle;
    ngx_pool_t           *pool;
    ngx_pool_t           *temp_pool;
    ngx_conf_file_t      *conf_file;
    ngx_log_t            *log;

    void                 *ctx;
    ngx_uint_t            module_type;
    ngx_uint_t            cmd_type;

    ngx_conf_handler_pt   handler;
    char                 *handler_conf;
};

b) ngx_conf_handler 进行配置的处理:

static ngx_int_t
ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
{
    char           *rv;
    void           *conf, **confp;
    ngx_uint_t      i, found;
    ngx_str_t      *name;
    ngx_command_t  *cmd;
 
    //1.参数名为数组第一个元素
    name = cf->args->elts;
 
    found = 0;
 
    //2.遍历模块找到cmd
    for (i = 0; ngx_modules[i]; i++) {
 
        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;
            }
 
            found = 1;
 
            if (ngx_modules[i]->type != NGX_CONF_MODULE
                && ngx_modules[i]->type != cf->module_type)
            {
                continue;
            }
 
            /* is the directive's location right ? */
 
            if (!(cmd->type & cf->cmd_type)) {
                continue;
            }
 
            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;
            }
 
            //3.校验参数个数
            /* 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;
            //4.1处理最上层的指令,每个模块一份
            if (cmd->type & NGX_DIRECT_CONF) {
                conf = ((void **) cf->ctx)[ngx_modules[i]->index];
 
            } else if (cmd->type & NGX_MAIN_CONF) {//4.2这样的配置包括event,http,三级指针,数组中存的是指针的指针,防止和NGX_DIRECT_CONF冲突
 
               conf = &(((void **) cf->ctx)[ngx_modules[i]->index]);
 
            } else if (cf->ctx) {//4.3处理http模块第一级指针代表http,serv,loc,第二级代表指定http,serv,loc的数组,第三级为内容
                confp = *(void **) ((char *) cf->ctx + cmd->conf);
 
                if (confp) {
                    conf = confp[ngx_modules[i]->ctx_index];
                }
            }
 
            //5.校验成功后,执行cmd->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;
        }
    }
 
    if (found) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "\"%s\" directive is not allowed here", name->data);
 
        return NGX_ERROR;
    }
 
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                       "unknown directive \"%s\"", name->data);
 
    return NGX_ERROR;
 
invalid:
 
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                       "invalid number of arguments in \"%s\" directive",
                       name->data);
 
    return NGX_ERROR;
}

c)cmd→set,以ngx_http模块为例:

static char *
ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    char                        *rv;
    ngx_uint_t                   mi, m, s;
    ngx_conf_t                   pcf;
    ngx_http_module_t           *module;
    ngx_http_conf_ctx_t         *ctx;
    ngx_http_core_loc_conf_t    *clcf;
    ngx_http_core_srv_conf_t   **cscfp;
    ngx_http_core_main_conf_t   *cmcf;
 
    /* the main http context */
 
    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
    if (ctx == NULL) {
        return NGX_CONF_ERROR;
    }
 
    *(ngx_http_conf_ctx_t **) conf = ctx;
 
 
    /* count the number of the http modules and set up their indices */
 
    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++;
    }
 
 
    /* the http main_conf context, it is the same in the all http contexts */
 
    ctx->main_conf = ngx_pcalloc(cf->pool,
                                 sizeof(void *) * ngx_http_max_module);
    if (ctx->main_conf == NULL) {
        return NGX_CONF_ERROR;
    }
 
 
    /*
     * the http null srv_conf context, it is used to merge
     * the server{}s' srv_conf's
     */
 
    ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
    if (ctx->srv_conf == NULL) {
        return NGX_CONF_ERROR;
    }
 
 
    /*
     * the http null loc_conf context, it is used to merge
     * the server{}s' loc_conf's
     */
 
    ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
    if (ctx->loc_conf == NULL) {
        return NGX_CONF_ERROR;
    }
 
 
    /*
     * create the main_conf's, the null srv_conf's, and the null loc_conf's
     * of the all http modules
     */
 
    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;
            }
        }
    }
 
    pcf = *cf;
    cf->ctx = ctx;
 
    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;
            }
        }
    }
 
    /* parse inside the http{} block */
 
    cf->module_type = NGX_HTTP_MODULE;
    cf->cmd_type = NGX_HTTP_MAIN_CONF;
    rv = ngx_conf_parse(cf, NULL);
 
    if (rv != NGX_CONF_OK) {
        goto failed;
    }
 
    /*
     * init http{} main_conf's, merge the server{}s' srv_conf's
     * and its location{}s' loc_conf's
     */
 
    cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
    cscfp = cmcf->servers.elts;
 
    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;
        }
    }
 
 
    /* create location trees */
 
    for (s = 0; s < cmcf->servers.nelts; s++) {
 
        clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
 
        if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
 
        if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    }
 
 
    if (ngx_http_init_phases(cf, cmcf) != NGX_OK) {
        return NGX_CONF_ERROR;
    }
 
    if (ngx_http_init_headers_in_hash(cf, cmcf) != NGX_OK) {
        return NGX_CONF_ERROR;
    }
 
 
    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;
            }
        }
    }
 
    if (ngx_http_variables_init_vars(cf) != NGX_OK) {
        return NGX_CONF_ERROR;
    }
 
    /*
     * http{}'s cf->ctx was needed while the configuration merging
     * and in postconfiguration process
     */
 
    *cf = pcf;
 
 
    if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {
        return NGX_CONF_ERROR;
    }
 
 
    /* optimize the lists of ports, addresses and server names */
 
    if (ngx_http_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) {
        return NGX_CONF_ERROR;
    }
 
    return NGX_CONF_OK;
 
failed:
 
    *cf = pcf;
 
    return rv;
}

rv = ngx_conf_parse(cf, NULL); 在初始化完http的上下文之后,继续进行内部的解析逻辑。这样就会调用到ngx_conf_handler的下面部分逻辑:

 confp = *(void **) ((char *) cf->ctx + cmd->conf);
 
                if (confp) {
                    conf = confp[ngx_modules[i]->ctx_index];
                }

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

core模块将会按照配置项的值在这个阶段进行初始化:

以ngx_event.c为例:

static char *
ngx_event_core_init_conf(ngx_cycle_t *cycle, void *conf)
{
    ngx_event_conf_t  *ecf = conf;
 
#if (NGX_HAVE_EPOLL) && !(NGX_TEST_BUILD_EPOLL)
    int                  fd;
#endif
#if (NGX_HAVE_RTSIG)
    ngx_uint_t           rtsig;
    ngx_core_conf_t     *ccf;
#endif
    ngx_int_t            i;
    ngx_module_t        *module;
    ngx_event_module_t  *event_module;
 
    module = NULL;
 
#if (NGX_HAVE_EPOLL) && !(NGX_TEST_BUILD_EPOLL)
 
    fd = epoll_create(100);
 
    if (fd != -1) {
        (void) close(fd);
        module = &ngx_epoll_module;
 
    } else if (ngx_errno != NGX_ENOSYS) {
        module = &ngx_epoll_module;
    }
 
#endif
 
#if (NGX_HAVE_RTSIG)
 
    if (module == NULL) {
        module = &ngx_rtsig_module;
        rtsig = 1;
 
    } else {
        rtsig = 0;
    }
 
#endif
 
#if (NGX_HAVE_DEVPOLL)
 
    module = &ngx_devpoll_module;
 
#endif
 
#if (NGX_HAVE_KQUEUE)
 
    module = &ngx_kqueue_module;
 
#endif
 
#if (NGX_HAVE_SELECT)
 
    if (module == NULL) {
        module = &ngx_select_module;
    }
 
#endif
 
    if (module == NULL) {
        for (i = 0; ngx_modules[i]; i++) {
 
            if (ngx_modules[i]->type != NGX_EVENT_MODULE) {
                continue;
            }
 
            event_module = ngx_modules[i]->ctx;
 
            if (ngx_strcmp(event_module->name->data, event_core_name.data) == 0)
            {
                continue;
            }
 
            module = ngx_modules[i];
            break;
        }
    }
 
    if (module == NULL) {
        ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "no events module found");
        return NGX_CONF_ERROR;
    }
 
    ngx_conf_init_uint_value(ecf->connections, DEFAULT_CONNECTIONS);
    cycle->connection_n = ecf->connections;
 
    ngx_conf_init_uint_value(ecf->use, module->ctx_index);
 
    event_module = module->ctx;
    ngx_conf_init_ptr_value(ecf->name, event_module->name->data);
 
    ngx_conf_init_value(ecf->multi_accept, 0);
    ngx_conf_init_value(ecf->accept_mutex, 1);
    ngx_conf_init_msec_value(ecf->accept_mutex_delay, 500);
 
 
#if (NGX_HAVE_RTSIG)
 
    if (!rtsig) {
        return NGX_CONF_OK;
    }
 
    if (ecf->accept_mutex) {
        return NGX_CONF_OK;
    }
 
    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
 
    if (ccf->worker_processes == 0) {
        return NGX_CONF_OK;
    }
 
    ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
                  "the \"rtsig\" method requires \"accept_mutex\" to be on");
 
    return NGX_CONF_ERROR;
 
#else
 
    return NGX_CONF_OK;
 
#endif
}

3.配置架构

3.1 整体结构

3.2 serv_conf结构

3.3 loc_conf结构

about_ngx_2.txt · 最后更改: 2018/10/14 15:31 (外部编辑)