当前位置: 首页 > 工具软件 > ngx-context > 使用案例 >

nginx源代码分析 - 启动(二) ngx_init_cycle - 解析配置文件

卢权
2023-12-01
cycle = ngx_init_cycle(&init_cycle);
ngx_timezone_update对于Linux系统来说,没做什么

tp = ngx_timeofday();得到ngx_cached_time
tp->sec = 0; 秒数清0
再次调用ngx_time_update
在新的slot存入新的time
更新相应的全局变量

log = old_cycle->log;沿用以前的log

pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
创建新pool,16 * 1024
pool->log = log;

cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t));分配加清0
cycle->pool = pool;
cycle->log = log;

cycle->old_cycle = old_cycle;

cycle->conf_param.data = ngx_pstrdup(pool, &old_cycle->conf_param);
old_cycle->conf_param是0x0,从pool上分配0字节实际上是返回了pool原来的最后一个有效数据地址,长度是0
拷贝只拷贝0字节,所以没有报错

cycle->paths.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *));
预分配10个ngx_path_t指针

cycle->config_dump

ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t)
list->part.elts预分配20个ngx_open_file_t

list->part.nelts = 0; //实际还没有元素,只是初始化空间了
list->part.next = NULL;
list->last = &list->part;
list->size = size; 元素大小
list->nalloc = n;
list->pool = pool;



ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t)
预分配1个ngx_shm_zone_t

为cycle->listening数组分配空间(n == 0)

ngx_queue_init(&cycle->reusable_connections_queue);

cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));
176个指针

cycle->hostname小写

ngx_cycle_modules(cycle)
cycle->modules = ngx_pcalloc(cycle->pool, (ngx_max_module + 1)
                                              * sizeof(ngx_module_t *));
178个ngx_module_t *指针(48 + 128)

ngx_memcpy(cycle->modules, ngx_modules,
               ngx_modules_n * sizeof(ngx_module_t *));
ngx_modules_n = 48拷贝ngx_modules指针

for (i = 0; cycle->modules[i]; i++) {遍历48个module,对core module(0x45524F43)
ngx_core_module_t  * module = cycle->modules[i]->ctx;

if (module->create_conf) {
    rv = module->create_conf(cycle);
    if (rv == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }
    cycle->conf_ctx[cycle->modules[i]->index] = rv;
}

1.ngx_core_module
ngx_core_module_create_conf
在cycle的pool中创建ngx_core_conf_t,赋上初始值
cycle->conf_ctx[cycle->modules[i]->index] = 刚创建的ngx_core_conf_t
4.ngx_regex_module,ngx_regex_create_conf
创建ngx_regex_conf_t,初始化,为链表字段预分配空间

2.ngx_errlog_module,无create_conf
5.ngx_events_module,无create_conf
8.ngx_http_module,无create_conf


3.ngx_conf_module,不是core module
6.ngx_event_core_module
7.ngx_epoll_module
9.ngx_http_core_module
10.ngx_http_log_module
...

创建一个临时的ngx_conf_t conf
创建conf.args,conf.temp_pool
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_param(&conf)
通过-g参数指定一些全局指令,这个函数有用,它会调用ngx_conf_parse(cf, NULL);,文件名指定为空,解析参数

ngx_conf_parse(&conf, &cycle->conf_file)
cf->conf_file可能有值,用prev变量保存,函数结束时再恢复

ngx_fd_info(fd, &cf->conf_file->file.info)
...
把配置文件的信息都保存在cf->conf_file中

然后进入循环,开始解析
ngx_conf_parse
    ngx_conf_read_token
    ngx_conf_handler
        find cmd
        rv = cmd->set(cf, cmd, conf);
    

获取第一个token,user,在ngx_core_module中找到user命令
conf = &(((void **) cf->ctx)[cf->cycle->modules[i]->index]);
rv = cmd->set(cf, cmd, conf);
然后回调ngx_set_user,cf参数仅获取value,conf参数会保存值
value = cf->args->elts; value指向的是2个string,str[0]是命令user,str[1]是命令的值liuwb
ccf->username = (char *) value[1].data;
pwd = getpwnam((const char *) value[1].data);
ccf->user = pwd->pw_uid;
ccf->group = grp->gr_gid;

worker_processes命令ngx_core_module模块ngx_set_worker_processes

error_log命令ngx_errlog_module模块,因为没有create conf,所以没有设置conf的值,而是直接用了ngx_log_set_log(cf, &dummy);
logs/error.log
new_log->file = ngx_conf_open_file(cf->cycle, &value[1]);
error.log,加入到&cycle->open_files列表
file->fd = NGX_INVALID_FILE; 暂时不打开
file->name = full;
ngx_log_set_levels(cf, new_log)设置level,也就是说errorlog后可以跟log文件和notice,info,debug这些级别,以空格隔开

pid命令ngx_core_module模块
ngx_conf_set_str_slot
ngx_core_conf_t类型offset 136,也就是pid字段,设置pid文件

events命令 ngx_events_module模块(也就是event后面必须写块,不用大括号括起来会报错)
ngx_events_block
ngx_count_modules 0x544e5645
    ngx_event_core_module
        ->ctx_index = 0
    ngx_epoll_module
        ->ctx_index = 1
返回2,赋给全局变量,ngx_event_max_module

ctx = ngx_pcalloc(cf->pool, sizeof(void *));
*ctx = ngx_pcalloc(cf->pool, ngx_event_max_module * sizeof(void *));
*(void **) conf = ctx;

对event模块(0x544e5645),如果有,则调用其create_conf方法
ngx_event_core_module->ngx_event_core_create_conf
创建ngx_event_conf_t,设为默认值,返回

ngx_epoll_module->ngx_epoll_create_conf
创建ngx_epoll_conf_t

创建临时ngx_conf_t,保存pcf = *cf;

cf->ctx = ctx;
cf->module_type = NGX_EVENT_MODULE;
cf->cmd_type = NGX_EVENT_CONF;

rv = ngx_conf_parse(cf, NULL);
cf->conf_file->file.fd != NGX_INVALID_FILE,没有文件名,但是cf的fd有效,就是解析block

use指令,ngx_event_core_module模块
ngx_event_use
找到模块名字和epool相等的模块,模块的名字不同于模块变量的名字,
module = cf->cycle->modules[m]->ctx; 模块的context,不同于cycle的ctx

ecf->use = cf->cycle->modules[m]->ctx_index; 1
ecf->name = module->name->data; epool
配置存到了上面创建的ngx_event_conf_t

worker_connections指令,ngx_event_core_module模块
ngx_event_connections
ecf->connections = ngx_atoi(value[1].data, value[1].len);
1024
cf->cycle->connection_n = ecf->connections;

block解析结束

恢复*cf = pcf;

下面要利用ctx,并给ctx初始化一些默认值。
(gdb) p ctx
$324 = (void ***) 0x730160
(gdb) p cf->ctx
$325 = (void *) 0x72e518

再遍历module数组,找到event类型的module
init_conf
ngx_event_core_init_conf
创建可以监听100个sock的epoll fd,再关闭
ngx_conf_init_uint_value(ecf->connections, DEFAULT_CONNECTIONS);
给cycle赋值,同时也给ecf置了一些默认值

ngx_epoll_init_conf
ngx_conf_init_uint_value(epcf->events, 512);
ngx_conf_init_uint_value(epcf->aio_requests, 32);


http指令 ngx_http_module模块
NGX_MAIN_CONF
conf = &(((void **) cf->ctx)[cf->cycle->modules[i]->index]);
ngx_http_block函数


ngx_http_conf_ctx_t *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;
创建一个局部的ctx并保存在全局配置数组里,index是7

ngx_http_max_module = ngx_count_modules(cf->cycle, NGX_HTTP_MODULE);
ngx_http_module不是NGX_HTTP_MODULE,而是NGX_CORE_MODULE,他的索引是7

cycle->old_cycle->modules = 0x0

总共40个http模块
为ctx->main_conf,ctx->srv_conf,ctx->loc_conf分配40个指针大小的内存

遍历40个http模块,查看模块是否有,create_main_conf,create_srv_conf,create_loc_conf
分别为指针创建结构体

如果模块有preconfiguration函数,则调用预配置函数

pcf = *cf;
cf->ctx = ctx;保存旧的cf,改变cf->ctx = ctx;
准备添加http配置
cf->module_type = NGX_HTTP_MODULE;
cf->cmd_type = NGX_HTTP_MAIN_CONF;
rv = ngx_conf_parse(cf, NULL);

include指令,ngx_conf_commands模块,ngx_conf_include方法
支持以通配符形式打开一系列文件,然后调用ngx_conf_parse(cf, &file);解析配置文件
解析/home/liuwb/Desktop/code/nginx-code/conf/mime.types文件

types指令,ngx_http_core_module模块,ngx_http_core_types方法
confp = *(void **) ((char *) cf->ctx + cmd->conf); confp指向ctx->loc_conf数组,
cmd->conf是loc_conf字段相对ngx_http_conf_ctx_t的偏移
conf = confp[cf->cycle->modules[i]->ctx_index]; i = 8, cf->cycle->modules[i]->ctx_index = 0

创建clcf->types数组,预分配64个ngx_hash_key_t的空间

save = *cf;
cf->handler = ngx_http_core_type; 开始使用handler
cf->handler_conf = conf;

rv = ngx_conf_parse(cf, NULL);
*cf = save;

(*cf->handler)(cf, NULL, cf->handler_conf);
ngx_http_core_type

ngx_http_core_loc_conf_t *clcf = conf; conf已经在create_loc_conf时分配了空间
将text/html html htm shtml都存在数组clcf->types中
type->key = value[i]; key是值本身
type->key_hash = hash; 计算hash值
type->value = content_type; 第一个元素是value,即text/html

下面所有的type都一样处理,存在数组clcf->types中
解析include文件结束
ngx_free(cf->conf_file->buffer->start);
ngx_close_file(fd)
cf->conf_file = prev;

default_type指令,ngx_http_core_module模块,ngx_conf_set_str_slot函数
conf指向ngx_http_conf_ctx_t的loc_conf的第0个元素,类型是ngx_http_core_loc_conf_t
default_type字段在ngx_http_core_loc_conf_t结构体中的偏移160,设置其值

log_format指令,ngx_http_log_module模块,ngx_http_log_set_format函数
conf指向ngx_http_conf_ctx_t的main_conf的第1个元素,类型是ngx_http_log_main_conf_t
fmt = lmcf->formats.elts;在create main conf的时候,已经设置了一个元素combined

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
将main加到lmcf->formats数组
ngx_http_log_compile_format(cf, fmt->flushes, fmt->ops, cf->args, 2);处理后面的格式
在ngx_http_log_vars中找remote_addr,找不到将remote_addr加到cmcf->variables数组中,并返回index,存入op,op再存到
ngx_http_log_fmt_t中,$开头的都这样处理,op->run = ngx_http_log_variable;

ngx_http_userid_add_variables在preconfiguration时添加了第一个元素

v = cmcf->variables.elts;
gdb) p v[0]
$367 = {name = {len = 9, data = 0x744a98 "uid_resetinclude"}, set_handler = 0x0, get_handler = 0x0, data = 0, flags = 0, index = 0}
(gdb) p v[1]
$368 = {name = {len = 11, data = 0x747458 "remote_addrremote_user"}, set_handler = 0x0, get_handler = 0x0, data = 0, flags = 0,
  index = 1}
(gdb) p v[2]
$369 = {name = {len = 11, data = 0x747463 "remote_user"}, set_handler = 0x0, get_handler = 0x0, data = 0, flags = 0, index = 2}


" - ","[", "]"这种符号也存在ops中
一条命令后面必须要跟分号结束,否则下一条命令还是这条命令的参数

sendfile指令,ngx_http_core_module模块
i=8,cf->cycle->modules[i]->ctx_index = 0
ngx_conf_set_flag_slot
取得字段offsetof(ngx_http_core_loc_conf_t, sendfile)
如果是on,则置1

keepalive_timeout指令,ngx_http_core_module模块
i=8,cf->cycle->modules[i]->ctx_index = 0
ngx_http_core_keepalive
ngx_http_core_loc_conf_t->keepalive_timeout = 65000

upstream指令,ngx_http_upstream_module,ngx_http_upstream函数
i=10, cf->cycle->modules[i]->ctx_index = 2
ngx_http_upstream_main_conf_t


ngx_url_t u; u.host = slb
ngx_http_upstream_add(cf, &u, NGX_HTTP_UPSTREAM_CREATE...)
创建ngx_http_upstream_srv_conf_t   *uscf
ngx_http_upstream_main_conf_t * umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);
uscfp = ngx_array_push(&umcf->upstreams); 放到配置结构体的数组里

在create_main_conf时,创建的ngx_http_upstream_main_conf_t umcf
ngx_array_init(&umcf->upstreams, cf->pool, 4, sizeof(ngx_http_upstream_srv_conf_t *)

(gdb) p *(ngx_http_upstream_main_conf_t *)((ngx_http_conf_ctx_t *)cf->ctx)->main_conf[2]
$449 = {headers_in_hash = {buckets = 0x0, size = 0}, upstreams = {elts = 0x730f88, nelts = 1, size = 8, nalloc = 4, pool = 0x72d4e0}}

(gdb) p *(ngx_http_upstream_srv_conf_t **)((ngx_http_upstream_main_conf_t *)((ngx_http_conf_ctx_t *)cf->ctx)->main_conf[2])->upstreams.elts
$459 = (ngx_http_upstream_srv_conf_t *) 0x7474a0

(gdb) p uscf
$460 = (ngx_http_upstream_srv_conf_t *) 0x7474a0

创建临时的ngx_http_conf_ctx_t
ngx_http_conf_ctx_t *ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
http_ctx = cf->ctx;保存旧的配置ngx_http_conf_ctx_t

ctx->main_conf = http_ctx->main_conf;临时的mian_conf指向旧的mian_conf
ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);40个指针
ctx->srv_conf[ngx_http_upstream_module.ctx_index] = uscf; //ngx_http_upstream_module.ctx_index = 2

uscf->srv_conf = ctx->srv_conf;

ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);

(gdb) p ctx
$461 = (ngx_http_conf_ctx_t *) 0x747508
(gdb) p cf->ctx
$462 = (void *) 0x7302a8

遍历一遍module数组,新建一套srv_conf数组,loc_conf数组

uscf->servers = ngx_array_create(cf->pool, 4, sizeof(ngx_http_upstream_server_t));
创建数组,预分配4个元素的空间

开始解析upstream块
pcf = *cf;
cf->ctx = ctx;
cf->cmd_type = NGX_HTTP_UPS_CONF;
rv = ngx_conf_parse(cf, NULL);
*cf = pcf;

upstream块下的
server指令,ngx_http_upstream_module模块,ngx_http_upstream_server函数
i = 10,cf->cycle->modules[i]->ctx_index = 2,offsetof(ngx_http_conf_ctx_t, srv_conf)
ngx_http_upstream_srv_conf_t配置

(gdb) p *(ngx_http_upstream_srv_conf_t*)((ngx_http_conf_ctx_t*)cf->ctx)->srv_conf[2]
$483 = {peer = {init_upstream = 0x0, init = 0x0, data = 0x0}, srv_conf = 0x747520, servers = 0x74aae0, flags = 319, host = {len = 3,
    data = 0x747497 "slb"}, file_name = 0x72d7a5 "/home/liuwb/Desktop/code/nginx-code/conf/nginx.conf", line = 36, port = 0,
  default_port = 0, no_port = 1, shm_zone = 0x0}

这个元素有值是因为上面执行了ctx->srv_conf[ngx_http_upstream_module.ctx_index] = uscf; //ngx_http_upstream_module.ctx_index = 2

0号元素就没有值
p *(ngx_http_core_srv_conf_t*)((ngx_http_conf_ctx_t*)cf->ctx)->srv_conf[0]
$484 = {server_names = {elts = 0x731d98, nelts = 0, size = 32, nalloc = 4, pool = 0x7314f0}, ctx = 0x0, server_name = {len = 0,
    data = 0x0}, connection_pool_size = 18446744073709551615, request_pool_size = 18446744073709551615,
  client_header_buffer_size = 18446744073709551615, large_client_header_buffers = {num = 0, size = 0},
  client_header_timeout = 18446744073709551615, ignore_invalid_headers = -1, merge_slashes = -1, underscores_in_headers = -1,
  listen = 0, captures = 0, named_locations = 0x0}

创建一个ngx_http_upstream_server_t,存入uscf->servers数组
(gdb) p *us
$493 = {name = {len = 18, data = 0x74ac48 "10.252.80.251:8082"}, addrs = 0x74ac68, naddrs = 1, weight = 1, max_conns = 0,
  max_fails = 1, fail_timeout = 10, slow_start = 0, down = 0, backup = 0}

下面又创建另一个server

那么为什么要创建一个ctx呢

http下的
server指令,ngx_http_core_module模块,ngx_http_core_server函数
i = 8, cf->cycle->modules[i]->ctx_index = 0
ngx_http_conf_ctx_t,  main_conf字段,第0个元素,类型ngx_http_core_main_conf_t

在之前ngx_http_core_main_conf_t的variables,variables_keys已经被填充过值
(gdb) p *(ngx_http_core_main_conf_t*)conf
$512 = {servers = {elts = 0x730900, nelts = 0, size = 8, nalloc = 4, pool = 0x72d4e0}, phase_engine = {handlers = 0x0,
    server_rewrite_index = 0, location_rewrite_index = 0}, headers_in_hash = {buckets = 0x0, size = 0}, variables_hash = {
    buckets = 0x0, size = 0}, variables = {elts = 0x7449b8, nelts = 4, size = 56, nalloc = 4, pool = 0x72d4e0}, ncaptures = 0,
  server_names_hash_max_size = 18446744073709551615, server_names_hash_bucket_size = 18446744073709551615,
  variables_hash_max_size = 18446744073709551615, variables_hash_bucket_size = 18446744073709551615, variables_keys = 0x731770,
  ports = 0x0, try_files = 0, phases = {{handlers = {elts = 0x0, nelts = 0, size = 0, nalloc = 0, pool = 0x0}} <repeats 11 times>}}

(gdb) p *(ngx_http_variable_t *)((ngx_http_core_main_conf_t*)conf)->variables.elts
$516 = {name = {len = 9, data = 0x744a98 "uid_resetinclude"}, set_handler = 0x0, get_handler = 0x0, data = 0, flags = 0, index = 0}

创建新的ngx_http_conf_ctx_t ctx
http_ctx = cf->ctx;
ctx->main_conf = http_ctx->main_conf; main_conf还是用旧的
创建新的ctx->srv_conf ,ctx->loc_conf,并遍历40个module,创建一遍相应配置

ngx_http_core_srv_conf_t *cscf = ctx->srv_conf[ngx_http_core_module.ctx_index]; 新地址
cscf->ctx = ctx;
ngx_http_core_main_conf_t *cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];

将cscf存入cmcf->servers数组中

开始解析server块
pcf = *cf;
cf->ctx = ctx;
cf->cmd_type = NGX_HTTP_SRV_CONF;
rv = ngx_conf_parse(cf, NULL);
*cf = pcf;

listen指令,ngx_http_core_module模块,ngx_http_core_listen函数
i = 8, cf->cycle->modules[i]->ctx_index = 0,cmd->conf = 8, 即ctx->srv_conf数组
实际上conf指向cscf

根据参数初始化ngx_http_listen_opt_t   lsopt;
ngx_http_add_listen(cf, cscf, &lsopt)
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);指向老的配置,因为main_conf没有改变

cmcf->ports = ngx_array_create(cf->temp_pool, 2, sizeof(ngx_http_conf_port_t));预分配2个
sa = &lsopt->sockaddr.sockaddr;
p = ngx_inet_get_port(sa); 得到端口80

创建port,加到cmcf->ports数组
port->family = sa->sa_family;
port->port = p;
port->addrs.elts = NULL;

ngx_http_add_address(cf, cscf, port, lsopt);
ngx_array_init(&port->addrs, cf->temp_pool, 4, sizeof(ngx_http_conf_addr_t)预分配数组
addr = ngx_array_push(&port->addrs);
addr->opt = *lsopt;
addr->hash.buckets = NULL;
addr->hash.size = 0;
addr->wc_head = NULL;
addr->wc_tail = NULL;
addr->nregex = 0;
addr->regex = NULL;

ngx_http_add_server(cf, cscf, addr);
ngx_array_init(&addr->servers, cf->temp_pool, 4, sizeof(ngx_http_core_srv_conf_t *)分配addr->servers数组
*server = cscf; cscf存入addr->servers数组

server_name指令,ngx_http_core_module模块,ngx_http_core_server_name函数
i = 8,cf->cycle->modules[i]->ctx_index = 0,cmd->conf = 8,即即ctx->srv_conf数组

ngx_http_core_srv_conf_t *cscf = conf
创建ngx_http_server_name_t  *sn;
sn->server = cscf;
sn->name = value[i];
sn放到cscf->server_names数组

location指令,ngx_http_core_module模块,ngx_http_core_location函数
i = 8,cf->cycle->modules[i]->ctx_index = 0,cmd->conf = 8,即即ctx->srv_conf数组
又创建了一个ngx_http_conf_ctx_t ctx
pctx = cf->ctx;
ctx->main_conf = pctx->main_conf;
ctx->srv_conf = pctx->srv_conf; main_conf和srv_conf都用老的
ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); loc_conf用新的

ngx_http_core_loc_conf_t  *clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
clcf->loc_conf = ctx->loc_conf;

ngx_http_core_loc_conf_t  *pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];这是旧的

ngx_http_add_location(cf, &pclcf->locations, clcf)
*locations = ngx_palloc(cf->temp_pool, sizeof(ngx_http_location_queue_t));
ngx_queue_init(*locations);

创建临时的ngx_http_location_queue_t  *lq;
lq->exact = NULL;
lq->inclusive = clcf;
lq->name = &clcf->name; "/" 路径
lq->file_name = cf->conf_file->file.name.data;
lq->line = cf->conf_file->line;

ngx_queue_insert_tail(*locations, &lq->queue);插入到locations队列

这样可以通过旧的pclcf找到clcf了,而clcf指向新的ctx里的某一地址,而且clcf->loc_conf = ctx->loc_conf;

save = *cf;
cf->ctx = ctx;
cf->cmd_type = NGX_HTTP_LOC_CONF;
rv = ngx_conf_parse(cf, NULL);
*cf = save;

proxy_pass指令,ngx_http_proxy_module模块,ngx_http_proxy_pass函数
i = 23,cf->cycle->modules[i]->ctx_index = 15,cmd->conf = 16
所有模块中23位,http模块中15位,ngx_http_conf_ctx_t的loc_conf数组的第15个元素,类型是ngx_http_proxy_loc_conf_t

ngx_http_proxy_loc_conf_t *plcf = conf;
ngx_http_core_loc_conf_t *clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);得到clcf
clcf->handler = ngx_http_proxy_handler; handler赋值
如果location以/结尾,clcf->auto_redirect = 1;
查看http://slb中是否有$, 如果有,
创建ngx_http_script_compile_t   sc;

ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

sc.cf = cf;
sc.source = url;
sc.lengths = &plcf->proxy_lengths;
sc.values = &plcf->proxy_values;
sc.variables = n;
sc.complete_lengths = 1;
sc.complete_values = 1;

ngx_http_script_compile(&sc)
    这个函数以后再debug
返回

这里没有
以http://开头
add = 7; 需要跳过7个字符
port = 80;

plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
ngx_http_upstream_main_conf_t  *umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);
ngx_http_conf_ctx_t的main_conf数组的第2个元素,ngx_http_upstream_main_conf_t,因为main_conf是和旧的公用的,所以这里可以用之前的配置

umcf->upstreams.nelts = 1,ngx_http_upstream_srv_conf_t **uscfp = umcf->upstreams.elts;
uscfp[i]->host.data = "slb", u->host = "slb",查找到了,返回uscfp[i],即ngx_http_upstream_srv_conf_t

如果没有找到,则创建ngx_http_upstream_srv_conf_t,存入umcf->upstreams数组

plcf->vars.schema.len = add; 7
plcf->vars.schema.data = url->data; http://slb
plcf->vars.key_start = plcf->vars.schema;

ngx_http_proxy_set_vars(&u, &plcf->vars);

plcf->location = clcf->name; /
plcf->url = *url;


又是server指令,
创建ngx_http_conf_ctx_t,公用main_conf, 创建新的srv_conf,loc_conf
ngx_http_core_srv_conf_t cscf指向新的srv_conf的第0个元素,cscf->ctx = ctx;
ngx_http_core_main_conf_t cmcf指向旧的main_conf的第0个元素
cscf存入cmcf->servers数组
开始解析server块

listen指令,取出cscf,创建port,加到cmcf->ports数组,*server = cscf; cscf存入addr->servers数组,addr来源于port

server_name指令,创建ngx_http_server_name_t  *sn;放到cscf->server_names数组

location指令,又创建了ngx_http_conf_ctx_t,和旧的公用main_conf,srv_conf
ngx_http_core_loc_conf_t  *clcf指向loc_conf的第0个元素,clcf->loc_conf = ctx->loc_conf;
clcf->name = *name;
pclcf->locations包含ngx_http_location_queue_t  *lq;,lq包含clcf
下面再解析location块

location下的proxy_pass指令,所有模块23,http模块15,即ngx_http_proxy_module模块
ngx_http_proxy_loc_conf_t *plcf指向loc数组的第15个元素
取出clcf,clcf->handler = ngx_http_proxy_handler;
plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0); 从main_conf中取出ngx_http_upstream_main_conf_t
查找有没有这个upstream,没有创建
plcf->location = clcf->name;

proxy_redirect指令,ngx_http_conf_ctx_t的loc_conf数组的第15个元素,总模块数23
ngx_http_proxy_redirect函数
plcf->redirect = 0;
plcf->redirects = NULL;

proxy_set_header指令,配置同上
ngx_conf_set_keyval_slot
取得ngx_http_proxy_loc_conf_t的headers_source字段,创建ngx_keyval_t,存入headers_source数组

当http的配置都解析完,回到ngx_http_block函数
ngx_http_core_main_conf_t   *cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
ngx_http_core_srv_conf_t   **cscfp = cmcf->servers.elts;

合并server,srv_conf,location
遍历所有http模块,如果模块有init_main_conf函数,则调用module->init_main_conf(cf, ctx->main_conf[mi]);
对所有http模块都调用ngx_http_merge_servers(cf, cmcf, module, mi);

8,0 ngx_http_core_init_main_conf

cscfp = cmcf->servers.elts;
ctx = (ngx_http_conf_ctx_t *) cf->ctx;
saved = *ctx;

遍历server数组,
ctx->srv_conf = cscfp[s]->ctx->srv_conf;
如果module->merge_srv_conf != NULL,
    module->merge_srv_conf(cf, saved.srv_conf[ctx_index], cscfp[s]->ctx->srv_conf[ctx_index]);
    ngx_http_core_merge_srv_conf,含义是如果cscfp[s]->ctx->srv_conf[ctx_index]中的某些项没有设置,用saved.srv_conf[ctx_index]
    的值替代,如果saved.srv_conf[ctx_index]也没有设置,就用默认值
如果module->merge_loc_conf != NULL,
    ngx_http_core_merge_loc_conf
    
    clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
    ngx_http_merge_locations(cf, clcf->locations, cscfp[s]->ctx->loc_conf, module, ctx_index);

创建location trees



NGX_HTTP_MODULE
ngx_http_core_module 0
    create_main_conf ngx_http_core_main_conf_t
    create_srv_conf ngx_http_core_srv_conf_t
    create_loc_conf ngx_http_core_loc_conf_t
    
    preconfiguration: ngx_http_core_preconfiguration
        ngx_http_variables_add_core_vars(cf);
            cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
            ((ngx_http_conf_ctx_t *) cf->ctx)->main_conf[module.ctx_index]
            ngx_http_core_module.ctx_index = 0
            
            cmcf->variables_keys = ngx_pcalloc(cf->temp_pool, sizeof(ngx_hash_keys_arrays_t));
            在temp_pool上分配hash表
            cmcf->variables_keys->pool = cf->pool;
            cmcf->variables_keys->temp_pool = cf->pool;
            
            ngx_hash_keys_array_init(cmcf->variables_keys, NGX_HASH_SMALL)
                asize = 4;
                ha->hsize = 107;
                ngx_array_init(&ha->keys, ha->temp_pool, asize, sizeof(ngx_hash_key_t))
                在ha->temp_pool中分配4个ngx_hash_key_t的空间
                ngx_array_init(&ha->dns_wc_head, ha->temp_pool, asize, sizeof(ngx_hash_key_t)
                ngx_array_init(&ha->dns_wc_tail, ha->temp_pool, asize, sizeof(ngx_hash_key_t)
                
                ha->keys_hash,ha->dns_wc_head_hash,ha->dns_wc_tail_hash给这3个指针创建空间
            
            遍历ngx_http_core_variables数组
                创建临时变量ngx_http_variable_t *v = ngx_palloc(cf->pool, sizeof(ngx_http_variable_t));
                *v = *cv;拷贝元素
                ngx_hash_add_key(cmcf->variables_keys, &v->name, v, NGX_HASH_READONLY_KEY);
                计算name的hash值,k %= ha->hsize;判断这个slot是否有其他元素,如果没有,则在这个槽位分配一个数组,
                ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4, sizeof(ngx_str_t))
                
                name = ngx_array_push(&ha->keys_hash[k]); name指向一个地址
                *name = *key;赋值
                
                hk = ngx_array_push(&ha->keys); 从ha->keys数组中腾出一个ngx_hash_key_t空间
                hk->key = *key; 字符串key
                hk->key_hash = ngx_hash_key(key->data, last); 保存其hash值
                hk->value = value; 对应的value,ngx_http_variable_t
                
ngx_http_log_module 1
    create_main_conf ngx_http_log_main_conf_t
    create_loc_conf ngx_http_log_loc_conf_t
ngx_http_upstream_module 2
    create_main_conf ngx_http_upstream_main_conf_t
    preconfiguration:ngx_http_upstream_add_variables
        遍历ngx_http_upstream_vars数组,每一个元素v
        ngx_http_variable_t *var = ngx_http_add_variable(cf, &v->name, v->flags);
            在上一步构造的hash表,cmcf->variables_keys->keys.elts中查找name,找到后即返回对应的ngx_http_variable_t
            没找到,则创建并初始化,并加到hash表中ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0);
        var->get_handler = v->get_handler;
        var->data = v->data;
        
        
ngx_http_static_module 3
ngx_http_autoindex_module 4
    create_loc_conf ngx_http_autoindex_loc_conf_t
ngx_http_index_module 5
    create_loc_conf ngx_http_index_loc_conf_t
ngx_http_auth_basic_module 6
    create_loc_conf ngx_http_auth_basic_loc_conf_t
ngx_http_access_module 7
    create_loc_conf ngx_http_access_loc_conf_t
ngx_http_limit_conn_module 8
    create_loc_conf ngx_http_limit_conn_conf_t
ngx_http_limit_req_module 9
    create_loc_conf ngx_http_limit_req_conf_t
ngx_http_geo_module 10
ngx_http_map_module 11
    create_main_conf ngx_http_map_conf_t
ngx_http_split_clients_module 12
ngx_http_referer_module 13
    create_loc_conf ngx_http_referer_conf_t
ngx_http_rewrite_module 14
    create_loc_conf ngx_http_rewrite_loc_conf_t
ngx_http_proxy_module 15
    全局变量定义了2个ngx_http_proxy_module,作为全局变量是可以的,如果放到函数体里,会报重定义错误
    create_main_conf ngx_http_proxy_main_conf_t
    create_loc_conf ngx_http_proxy_loc_conf_t
    
    ngx_http_proxy_add_variables
        将ngx_http_proxy_vars数组中的元素加入到cmcf->variables_keys表中
ngx_http_fastcgi_module 16
    create_main_conf ngx_http_fastcgi_main_conf_t
    create_loc_conf ngx_http_fastcgi_loc_conf_t
    ngx_http_fastcgi_add_variables:添加数组ngx_http_fastcgi_vars
ngx_http_uwsgi_module 17
    create_main_conf ngx_http_uwsgi_main_conf_t
    create_loc_conf ngx_http_uwsgi_loc_conf_t
ngx_http_scgi_module 18
    create_main_conf ngx_http_scgi_main_conf_t
    create_loc_conf ngx_http_scgi_loc_conf_t
ngx_http_memcached_module 19
    create_loc_conf ngx_http_memcached_loc_conf_t
ngx_http_empty_gif_module 20
ngx_http_browser_module
    create_loc_conf ngx_http_browser_conf_t
    添加ngx_http_browsers数组
ngx_http_upstream_hash_module
    create_srv_conf ngx_http_upstream_hash_srv_conf_t
ngx_http_upstream_ip_hash_module
ngx_http_upstream_least_conn_module
ngx_http_upstream_keepalive_module
    create_srv_conf ngx_http_upstream_keepalive_srv_conf_t
ngx_http_upstream_zone_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
    create_loc_conf ngx_http_gzip_conf_t
    ngx_http_gzip_add_variables: 只添加一个变量ngx_http_gzip_ratio
ngx_http_postpone_filter_module
ngx_http_ssi_filter_module
    create_main_conf ngx_http_ssi_main_conf_t
    create_loc_conf ngx_http_ssi_loc_conf_t
    ngx_http_ssi_preconfiguration:ngx_http_ssi_vars数组
ngx_http_charset_filter_module
    create_main_conf ngx_http_charset_main_conf_t
    create_loc_conf ngx_http_charset_loc_conf_t
ngx_http_userid_filter_module
    create_loc_conf ngx_http_userid_conf_t
    ngx_http_userid_add_variables:添加元素ngx_http_userid_got,ngx_http_userid_set,ngx_http_userid_reset
    并得到ngx_http_userid_reset在hash表中的index,保存在静态变量ngx_http_userid_reset_index中
    
ngx_http_headers_filter_module
    create_loc_conf ngx_http_headers_conf_t
ngx_http_copy_filter_module
    create_loc_conf ngx_http_copy_filter_conf_t
ngx_http_range_body_filter_module
ngx_http_not_modified_filter_module 39




配置最后的结构
ngx_conf_t conf {
    ...
    void *ctx;
    ...
}
ngx_cycle_t cycle {}
    void ****conf_ctx;
    ...
}
conf.ctx = cycle->conf_ctx;

(gdb) p *(ngx_core_conf_t *)((void **)conf.ctx)[0]
$5 = {daemon = -1, master = -1, timer_resolution = 18446744073709551615, worker_processes = 2, debug_points = -1, rlimit_nofile = -1,
  rlimit_core = -1, priority = 0, cpu_affinity_auto = 0, cpu_affinity_n = 0, cpu_affinity = 0x0, username = 0x7300d6 "liuwb",
  user = 1000, group = 1000, working_directory = {len = 0, data = 0x0}, lock_file = {len = 0, data = 0x0}, pid = {len = 14,
    data = 0x730146 "logs/nginx.pid"}, oldpid = {len = 0, data = 0x0}, env = {elts = 0x72f100, nelts = 0, size = 16, nalloc = 1,
    pool = 0x72d4e0}, environment = 0x0}

(gdb) p ((void **)conf.ctx)[1]
$6 = (void *) 0x0    是因为ngx_errlog_module,无create_conf

(gdb) p *(ngx_regex_conf_t *)((void **)conf.ctx)[3]
$9 = {pcre_jit = -1}

多维配置,event的配置
void *conf = &(((void **) cf->ctx)[cf->cycle->modules[i]->index]);
cf->cycle->modules[i]->index = 4
这里的cf就是上面的conf
新的conf指向((void **)conf.ctx)[4]的地址,用来改变((void **)conf.ctx)[4]的值
((void **)conf.ctx)[4]的值(加一)又是一个指针数组(加二),所以这个元素的类型是三维指针

(gdb) p *(ngx_event_conf_t *)(*(void ***)((void **)conf.ctx)[4])[0]
$31 = {connections = 1024, use = 1, multi_accept = 0, accept_mutex = 0, accept_mutex_delay = 500, name = 0x4dd318 "epoll",
  debug_connection = {elts = 0x7301d0, nelts = 0, size = 40, nalloc = 4, pool = 0x72d4e0}}

(gdb) p *(ngx_epoll_conf_t *)(*(void ***)((void **)conf.ctx)[4])[1]
$32 = {events = 512, aio_requests = 32}

像ngx_http_conf_ctx_t  采用了不同的策略,
((void **)conf.ctx)[7]的值是ngx_http_conf_ctx_t指针,在ngx_http_conf_ctx_t结构里再布局

 类似资料: