【nginx流程分析之初始化cycle】

本文详细解析了nginx启动时cycle对象的初始化过程,涉及变量和config赋值、array初始化、config_dump_rbtree红黑树、单向链表和queue的设置,以及hostname获取和配置文件读取关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

继承上一篇【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流程分析之配置文件读取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值