【nginx流程分析之初始化cycle】
继承上一篇【nginx流程分析】。我们开始说cycle的初始化。其实就是ngx_init_cycle的方法
因为这里有很多的指针操作,我们单独开了一篇专门说一下中间的指针操作,详见nginx流程分析之指针操作
变量初始化和赋值
因为变量初始化和config的赋值比较简单,我们就在代码中增加注释说明,这边的config文件都是在运行nginx的时候没有指定前缀的结果。对于变量可以看【nginx流程分析之变量篇】
void *rv;
char **senv;
ngx_uint_t i, n;
ngx_log_t *log;
ngx_time_t *tp;
ngx_conf_t conf;
ngx_pool_t *pool;
ngx_cycle_t *cycle, **old;
ngx_shm_zone_t *shm_zone, *oshm_zone;
ngx_list_part_t *part, *opart;
ngx_open_file_t *file;
ngx_listening_t *ls, *nls;
ngx_core_conf_t *ccf, *old_ccf;
ngx_core_module_t *module;
char hostname[NGX_MAXHOSTNAMELEN];
//更新时区
ngx_timezone_update();
/* force localtime update with a new timezone */
//获取当时时间和时间更新
tp = ngx_timeofday();
tp->sec = 0;
ngx_time_update();
log = old_cycle->log;
//分配内存池
//NGX_CYCLE_POOL_SIZE = (16 * 1024)
pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
if (pool == NULL) {
return NULL;
}
pool->log = log;
//分配cycle的内存
cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t));
if (cycle == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
//赋值
cycle->pool = pool;
cycle->log = log;
cycle->old_cycle = old_cycle;
// cycle->conf_prefix = /usr/local/nginx/conf/
cycle->conf_prefix.len = old_cycle->conf_prefix.len;
cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix);
if (cycle->conf_prefix.data == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
// cycle->prefix. = /usr/local/nginx/
cycle->prefix.len = old_cycle->prefix.len;
cycle->prefix.data = ngx_pstrdup(pool, &old_cycle->prefix); ///usr/local/nginx/
if (cycle->prefix.data == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
// cycle->conf_file = /usr/local/nginx/conf/nginx.conf
cycle->conf_file.len = old_cycle->conf_file.len;
cycle->conf_file.data = ngx_pnalloc(pool, old_cycle->conf_file.len + 1); ///usr/local/nginx/conf/nginx.conf
if (cycle->conf_file.data == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
//对 cycle->conf_file.data 进行赋值
ngx_cpystrn(cycle->conf_file.data, old_cycle->conf_file.data,
old_cycle->conf_file.len + 1);
// cycle->conf_param = null
cycle->conf_param.len = old_cycle->conf_param.len;
cycle->conf_param.data = ngx_pstrdup(pool, &old_cycle->conf_param); //null
if (cycle->conf_param.data == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
初始化array
我们先看一下nginx接下来初始化的代码
//之前没有初始化 所以 n =10
n = old_cycle->paths.nelts ? old_cycle->paths.nelts : 10;
//sizeof(ngx_path_t *) 是指针 8个字节
//所以是长度是n 内存大小是 n*8
if (ngx_array_init(&cycle->paths, pool, n, sizeof(ngx_path_t *))
!= NGX_OK)
{
ngx_destroy_pool(pool);
return NULL;
}
ngx_memzero(cycle->paths.elts, n * sizeof(ngx_path_t *))
//同上 长度是1
//内存大小是 1 * 8
if (ngx_array_init(&cycle->config_dump, pool, 1, sizeof(ngx_conf_dump_t))
!= NGX_OK)
{
ngx_destroy_pool(pool);
return NULL;
}
然后看一下ngx_array_init的具体实现
typedef struct {
void *elts; //数组首地址
ngx_uint_t nelts; //已使用的元素个数
size_t size; //每个元素的大小
ngx_uint_t nalloc; //整个数组长度
ngx_pool_t *pool; //数组所在的内存池
} ngx_array_t;
static ngx_inline ngx_int_t
ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
/*
* set "array->nelts" before "array->elts", otherwise MSVC thinks
* that "array->nelts" may be used without having been initialized
*/
array->nelts = 0; //已使用的元素个数设置为0
array->size = size;//设置长度
array->nalloc = n;//整个数组长度 设置为n
array->pool = pool; //对应的内存池
//从内存池中获取 n* size大小的内存,并将地址指向elts
array->elts = ngx_palloc(pool, n * size);
if (array->elts == NULL) {
return NGX_ERROR;
}
return NGX_OK;
}
初始化config_dump_rbtree红黑树
先看一下代码
ngx_rbtree_init(&cycle->config_dump_rbtree, &cycle->config_dump_sentinel,ngx_str_rbtree_insert_value);
然后看一下ngx_rbtree_init 的实现,以及ngx_rbtree_sentinel_init的实现
#define ngx_rbtree_init(tree, s, i) \
ngx_rbtree_sentinel_init(s); \
(tree)->root = s; \
(tree)->sentinel = s; \
(tree)->insert = i
/* a sentinel must be black */
#define ngx_rbtree_sentinel_init(node) ngx_rbt_black(node)
#define ngx_rbt_black(node) ((node)->color = 0)
然后其实就是把 cycle->config_dump_rbtree当做红黑树的树,然后config_dump_sentinel当做节点,同时config_dump_sentinel 设置为黑色节点。然后insert方法就是ngx_str_rbtree_insert_value。然后我们看一下实现
void
ngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp,
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
{
ngx_str_node_t *n, *t;
ngx_rbtree_node_t **p;
for ( ;; ) {
n = (ngx_str_node_t *) node;
t = (ngx_str_node_t *) temp;
if (node->key != temp->key) {
p = (node->key < temp->key) ? &temp->left : &temp->right;
} else if (n->str.len != t->str.len) {
p = (n->str.len < t->str.len) ? &temp->left : &temp->right;
} else {
p = (ngx_memcmp(n->str.data, t->str.data, n->str.len) < 0)
? &temp->left : &temp->right;
}
if (*p == sentinel) {
break;
}
temp = *p;
}
*p = node;
node->parent = temp;
node->left = sentinel;
node->right = sentinel;
ngx_rbt_red(node);
}
因为这里只是做了初始化,后面我们用到了再细说。
初始化单向链表,queue和获取hostname
接下来还是初始化的一些操作,在注释里面做了备注
//old_cycle->open_files.part.nelts 为初始化 n=20
if (old_cycle->open_files.part.nelts) {
n = old_cycle->open_files.part.nelts;
for (part = old_cycle->open_files.part.next; part; part = part->next) {
n += part->nelts;
}
} else {
n = 20;
}
//初始化open_files的一个单向链表
//n长度为n 这里为20
//每个元素大小为 sizeof(ngx_open_file_t) 这里为40
if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t))
!= NGX_OK)
{
ngx_destroy_pool(pool);
return NULL;
}
if (old_cycle->shared_memory.part.nelts) {
n = old_cycle->shared_memory.part.nelts;
for (part = old_cycle->shared_memory.part.next; part; part = part->next)
{
n += part->nelts;
}
} else {
n = 1;
}
//初始化shared_memory的一个单向链表
//n长度为n 这里为1
//每个元素大小为 sizeof(ngx_open_file_t) 这里为88
if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t))
!= NGX_OK)
{
ngx_destroy_pool(pool);
return NULL;
}
n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10;
//初始化listening的数组
//长度为10
//每个元素大小为 sizeof(ngx_listening_t) 这里为224
printf("sizeof(ngx_listening_t):%lu\n",sizeof(ngx_listening_t));
if (ngx_array_init(&cycle->listening, pool, n, sizeof(ngx_listening_t))
!= NGX_OK)
{
ngx_destroy_pool(pool);
return NULL;
}
//制空listening.elts数组 保证每个元素是空
ngx_memzero(cycle->listening.elts, n * sizeof(ngx_listening_t));
//初始化cycle->reusable_connections_queue的双向链表
ngx_queue_init(&cycle->reusable_connections_queue);
//分配ngx_max_module*8字节大小的内存 在ngx_preinit_modules方法中 ngx_max_module为178
cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));
if (cycle->conf_ctx == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
//获取主机名称存入hostname
if (gethostname(hostname, NGX_MAXHOSTNAMELEN) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "gethostname() failed");
ngx_destroy_pool(pool);
return NULL;
}
/* on Linux gethostname() silently truncates name that does not fit */
hostname[NGX_MAXHOSTNAMELEN - 1] = '\0';
cycle->hostname.len = ngx_strlen(hostname);
cycle->hostname.data = ngx_pnalloc(pool, cycle->hostname.len);
if (cycle->hostname.data == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
//将hostname存入到cycle->hostname中
ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len);
//old_cycle->open_files.part.nelts 为初始化 n=20
if (old_cycle->open_files.part.nelts) {
n = old_cycle->open_files.part.nelts;
for (part = old_cycle->open_files.part.next; part; part = part->next) {
n += part->nelts;
}
} else {
n = 20;
}
//初始化open_files的一个单向链表
//n长度为n 这里为20
//每个元素大小为 sizeof(ngx_open_file_t) 这里为40
if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t))
!= NGX_OK)
{
ngx_destroy_pool(pool);
return NULL;
}
if (old_cycle->shared_memory.part.nelts) {
n = old_cycle->shared_memory.part.nelts;
for (part = old_cycle->shared_memory.part.next; part; part = part->next)
{
n += part->nelts;
}
} else {
n = 1;
}
//初始化shared_memory的一个单向链表
//n长度为n 这里为1
//每个元素大小为 sizeof(ngx_open_file_t) 这里为88
if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t))
!= NGX_OK)
{
ngx_destroy_pool(pool);
return NULL;
}
n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10;
//初始化listening的数组
//长度为10
//每个元素大小为 sizeof(ngx_listening_t) 这里为224
printf("sizeof(ngx_listening_t):%lu\n",sizeof(ngx_listening_t));
if (ngx_array_init(&cycle->listening, pool, n, sizeof(ngx_listening_t))
!= NGX_OK)
{
ngx_destroy_pool(pool);
return NULL;
}
//制空listening.elts数组 保证每个元素是空
ngx_memzero(cycle->listening.elts, n * sizeof(ngx_listening_t));
//初始化cycle->reusable_connections_queue的双向链表
ngx_queue_init(&cycle->reusable_connections_queue);
//分配ngx_max_module*8字节大小的内存 在ngx_preinit_modules方法中 ngx_max_module为178
cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));
if (cycle->conf_ctx == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
//获取主机名称存入hostname
if (gethostname(hostname, NGX_MAXHOSTNAMELEN) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "gethostname() failed");
ngx_destroy_pool(pool);
return NULL;
}
/* on Linux gethostname() silently truncates name that does not fit */
hostname[NGX_MAXHOSTNAMELEN - 1] = '\0';
cycle->hostname.len = ngx_strlen(hostname);
cycle->hostname.data = ngx_pnalloc(pool, cycle->hostname.len);
if (cycle->hostname.data == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
//将hostname存入到cycle->hostname中
ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len);
//将ngx_modules 赋值给 cycle->modules
//将ngx_modules_n 赋值给 cycle->modules_n 这里为48
if (ngx_cycle_modules(cycle) != NGX_OK) {
ngx_destroy_pool(pool);
return NULL;
}
初始化读取配置文件
接下来就是初始化配置文件,然后初始化临时对象池的操作
for (i = 0; cycle->modules[i]; i++) {
//判断是否是核心模块
if (cycle->modules[i]->type != NGX_CORE_MODULE) {
continue;
}
//核心模块 就是nginx.c中的 ngx_core_module
//ctx 是 nginx.c中的ngx_core_module_ctx
module = cycle->modules[i]->ctx;
//判断是否有create_conf这个方法
//其实这个就是 nginx.c中的ngx_core_module_create_conf放
if (module->create_conf) {
//其实初始化了 ngx_core_conf_t *ccf 这个配置文件
rv = module->create_conf(cycle);
if (rv == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
//放到了cycle->conf_ctx中的conf_ctx中
cycle->conf_ctx[cycle->modules[i]->index] = rv;
}
}
senv = environ;
ngx_memzero(&conf, sizeof(ngx_conf_t));
/* STUB: init array ? */
printf("sizeof(ngx_str_t):%lu\n",sizeof(ngx_str_t));
//初始化conf.args的数组
conf.args = ngx_array_create(pool, 10, sizeof(ngx_str_t));
if (conf.args == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
//创建临时变量池
//大小为 NGX_CYCLE_POOL_SIZE = 16 * 1024
conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
if (conf.temp_pool == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
//进行初始化
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;
读取配置文件并获取值
首先我们看一下对应的代码
//因为此时cf->cycle->conf_param为空所以这个方法没有作用
if (ngx_conf_param(&conf) != NGX_CONF_OK) {
environ = senv;
ngx_destroy_cycle_pools(&conf);
return NULL;
}
//解析配置文件
if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {
environ = senv;
ngx_destroy_cycle_pools(&conf);
return NULL;
}
因为解析配置文件内容比较多,所以我们单开一篇文章,详见nginx流程分析之配置文件读取