Nginx源码剖析--ngx_cycle_t的初始化

前言

前一篇介绍了ngx_cycle_t中各个成员的具体含义,虽然许多成员具体作用和实现方式我们没有深究,但也有了一个初步的了解。这篇文章将介绍ngx_cycle_t的初始化过程,主要是在ngx_init_cycle函数中完成的,之所以说主要,因为ngx_cycle_t的初始化还会依赖于一个old_cycle,这个old_cycle的初始化是在main中完成的。ngx_init_cycle的函数原型如下

ngx_cycle_t *
ngx_init_cycle(ngx_cycle_t *old_cycle)

old_cycle将作为参数被传进去,因此实际的ngx_cycle的部分成员会参考old_cycle的相应成员做初始化。因此我们先介绍一下old_cycle的初始化,然后介绍ngx_init_cycle函数的实现。


old_cycle初始化

old_cycle的初始化在main函数中进行。它的初始化主要分为两方面,一是根据启动nginx时的命令行参数做初始化,二是根据继承而来的参数做初始化。这里之所以会有继承,是因为nginx支持平滑升级,升级过程由master进程完成,简单来说就是master启动一个新的进程执行升级后的服务器程序,因此所谓继承就是根据未升级时的环境,参数设置新进程的环境,参数等。

下面具体看一下代码,main函数中的init_cycle就是ngx_init_cycle中的old_cycle。

1. 初始化log, pool
    ngx_memzero(&init_cycle, sizeof(ngx_cycle_t));
    init_cycle.log = log;
    ngx_cycle = &init_cycle;

    init_cycle.pool = ngx_create_pool(1024, log);
    if (init_cycle.pool == NULL) {
        return 1;
    }

这些没什么好说的。需要注意的是,ngx_cycle是一个全局变量。

   if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) {
        return 1;
    }

这个函数其实没有初始化init_cycle,它只是将命令行参数保存到一些全局变量中。这里之所以要列出这个函数主要是为了了解init_cycle->log的作用。它是做日志的。

2. 初始化conf_file,conf_param,conf_prefix,prefix
if (ngx_process_options(&init_cycle) != NGX_OK) {
        return 1;
    }
3. 初始化cycle->listening
    if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) {
        return 1;
    }

这里就是前面说的继承(平滑升级)起作用的地方。这个函数的作用就是根据未升级时nginx的listening结构初始化init_cycle.

至此,old_cycle(init_cycle)就初始化完毕了。下面将进入ngx_init_cycle函数中

cycle = ngx_init_cycle(&init_cycle);

这个返回的cycle才是正在nginx运行所依赖的ngx_cycle_t。


ngx_init_cycle函数的实现

1. 创建cycle结构体
cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t));
2.初始化pool
    cycle->pool = pool;

这个pool是新建的,并不是从old_cycle继承而来。

3. 初始化log,conf_param,conf_file,prefix,conf_prefix,old_cycle
   cycle->log = log;
    cycle->old_cycle = old_cycle;

    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.len = old_cycle->prefix.len;
    cycle->prefix.data = ngx_pstrdup(pool, &old_cycle->prefix);
    if (cycle->prefix.data == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }

    cycle->conf_file.len = old_cycle->conf_file.len;
    cycle->conf_file.data = ngx_pnalloc(pool, old_cycle->conf_file.len + 1);
    if (cycle->conf_file.data == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }
    ngx_cpystrn(cycle->conf_file.data, old_cycle->conf_file.data,
                old_cycle->conf_file.len + 1);

    cycle->conf_param.len = old_cycle->conf_param.len;
    cycle->conf_param.data = ngx_pstrdup(pool, &old_cycle->conf_param);
    if (cycle->conf_param.data == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }

这里的初始化就都是从old_cycle继承而来的了。

4. 初始化paths
   cycle->paths.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *));
    if (cycle->paths.elts == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }

    cycle->paths.nelts = 0;
    cycle->paths.size = sizeof(ngx_path_t *);
    cycle->paths.nalloc = n;
    cycle->paths.pool = pool;
5. 初始化open_files
   if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t))
        != NGX_OK)
    {
        ngx_destroy_pool(pool);
        return NULL;
    }
6.初始化shared_memory
    if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t))
        != NGX_OK)
    {
        ngx_destroy_pool(pool);
        return NULL;
    }
7. 初始化listening
    cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t));
    if (cycle->listening.elts == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }

    cycle->listening.nelts = 0;
    cycle->listening.size = sizeof(ngx_listening_t);
    cycle->listening.nalloc = n;
    cycle->listening.pool = pool;
8. 初始化reusable_connections_queue
 ngx_queue_init(&cycle->reusable_connections_queue);
9. 初始化hostname
    if (gethostname(hostname, NGX_MAXHOSTNAMELEN) == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "gethostname() failed");
        ngx_destroy_pool(pool);
        return NULL;
    }
    ......
10. 初始化conf_ctx

这部分是初始化conf_ctx,是ngx_init_cycle的大头。主要作用就是创建加载设置nginx中所有模块的配置结构体,并把所有这些配置结构体组织到conf_ctx中。我们后面会详细分析这部分代码。这段代码的核心就是解析配置文件。

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


    senv = environ;


    ngx_memzero(&conf, sizeof(ngx_conf_t));  // 对conf的初始化
    /* STUB: init array ? */
    conf.args = ngx_array_create(pool, 10, sizeof(ngx_str_t));
    if (conf.args == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }

    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;

#if 0
    log->log_level = NGX_LOG_DEBUG_ALL;
#endif

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

    if (ngx_test_config && !ngx_quiet_mode) {
        ngx_log_stderr(0, "the configuration file %s syntax is ok",
                       cycle->conf_file.data);
    }

    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;
            }
        }
    }
11.初始化new_log
if (ngx_log_open_default(cycle) != NGX_OK) {
        goto failed;
    }


到这里,基本上对cycle成员的初始化差不多完成了,其他几个没有被初始化的成员包括:lock_file,write_events,read_events,connections,connection_n,files_n,files,free_connections,free_connection_n。

这些成员都是跟进程处理的连接数有关的,因此都是动态变化的。后面我们在详细分析这些成员。

12.剩下的工作

ngx_init_cycle对cycle中成员的初始化到此可以认为结束了,函数后面的部分主要是完成以下两项工作:

  1. 设置成员的属性,或者根据初始化的文件名打开文件,创建共享内存,设置监听套接口的属性等。

  2. 除此之外,函数后部分还会做一些善后工作,主要是释放old_cycle中的一些没用的资源,包括释放共享内存,关闭没用的套接口,关闭打开的没用文件,最后将这个old_cycle放入到全局变量ngx_old_cycles队列中。


总结

这篇文章主要是介绍了ngx_cycle_t的初始化过程。cycle的初始化依赖于两部分,一部分是old_cycle,一部分是在ngx_init_cycle函数中。old_cycle主要是保存一些命令行,从旧进程继承而来的设置。在ngx_cycle_init函数中,除了完成对绝大多数cycle成员的初始化之外,还会对成员的属性进行一些设置,比如对listening队列中的监听结构进行套接字属性设置,比如打开共享内存,打开文件等等;另一方面,ngx_cycle_init函数还会完成初始化后的善后工作,主要是释放old_cycle中没用的资源,毕竟old_cycle的使命已经结束了,它不应该占用没用的资源了。

总的来说,我们基本了解了ngx_cycle的初始化执行过程。当然还不完全,比如cycle中有部分成员到这里还没有被初始化。后面我们会一一进行介绍。

猜你喜欢

转载自blog.csdn.net/swartz2015/article/details/78144893