Chinaunix首页 | 论坛 | 博客
  • 博客访问: 371411
  • 博文数量: 56
  • 博客积分: 1449
  • 博客等级: 中尉
  • 技术积分: 822
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-08 10:24
文章分类

全部博文(56)

文章存档

2014年(7)

2012年(13)

2011年(10)

2010年(26)

分类: 服务器与存储

2014-08-12 20:02:17

ngx_cycle_t 是nginx中的核心数据结构. 主框架代码围绕这个数据结构来展开.
ngx_init_cycle函数创建并初始化ngx_cycle_t结构, 并且初始化nginx的模块.
下面以第一次启动nginx并且是以master方式运行. 来看ngx_init_cycle函数所做的事情.

点击(此处)折叠或打开

  1. ngx_timezone_update();
  2. ngx_time_update();
更新时区. 从其实现方式来看, 在linux中, 通过调用strftime可以达到更新时区的目的, strftime会调用tzset来读取存储在/etc/localtime中的时区信息
更新时区之后, 调用ngx_time_update来更新缓存的时间. 为了减少调用获取时间的函数的次数, nginx在一定的时间精度内将时间缓存起来. 获取时间只需要一次内存访问即可.

点击(此处)折叠或打开

  1. pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
  2. cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t));
先分配一个16KB的内存池, 然后在这个内存池中分配ngx_cycle_t结构, ngx_cycle_t就这样诞生了.
接下来所做的事情就是将old_cycle中的prefix, conf_prefix, conf_file这几个字段拷贝过来. 注意是深拷贝,
这些字段是在ngx_process_options函数中初始化的. 代码就不贴出来了.

点击(此处)折叠或打开

  1. n = old_cycle->paths.nelts ? old_cycle->paths.nelts : 10;

  2.     cycle->paths.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *));
  3.     if (cycle->paths.elts == NULL) {
  4.         ngx_destroy_pool(pool);
  5.         return NULL;
  6.     }

  7.     cycle->paths.nelts = 0;
  8.     cycle->paths.size = sizeof(ngx_path_t *);
  9.     cycle->paths.nalloc = n;
  10.     cycle->paths.pool = pool;
初始化动态数组cycle->paths, 预留10个元素的内存空间. 等价于 ngx_array_init(&cycle->paths, pool, n, sizeof(ngx_path_t *)).
关于nginx的动态数组见http://blog.chinaunix.net/uid-22577711-id-4389317.html

点击(此处)折叠或打开

  1. if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t))
  2.         != NGX_OK)
初始化链表cycle->open_files, 预留空间为20.

点击(此处)折叠或打开

  1. if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t))
  2.         != NGX_OK)
初始化链表cycle->shared_memory, 预留空间为1.

点击(此处)折叠或打开

  1. n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10;

  2.     cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t));
  3.     if (cycle->listening.elts == NULL) {
  4.         ngx_destroy_pool(pool);
  5.         return NULL;
  6.     }

  7.     cycle->listening.nelts = 0;
  8.     cycle->listening.size = sizeof(ngx_listening_t);
  9.     cycle->listening.nalloc = n;
  10.     cycle->listening.pool = pool;
初始化动态数组cycle->listening, 预留空间为10.

点击(此处)折叠或打开

  1. ngx_queue_init(&cycle->reusable_connections_queue);
初始化队列cycle->reusable_connections_queue.

点击(此处)折叠或打开

  1. cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));
分配用于保存所有模块配置上下文指针的数组.

点击(此处)折叠或打开

  1. if (gethostname(hostname, NGX_MAXHOSTNAMELEN) == -1) {
  2.         ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "gethostname() failed");
  3.         ngx_destroy_pool(pool);
  4.         return NULL;
  5.     }

  6.     /* on Linux gethostname() silently truncates name that does not fit */

  7.     hostname[NGX_MAXHOSTNAMELEN - 1] = '\0';
  8.     cycle->hostname.len = ngx_strlen(hostname);

  9.     cycle->hostname.data = ngx_pnalloc(pool, cycle->hostname.len);
  10.     if (cycle->hostname.data == NULL) {
  11.         ngx_destroy_pool(pool);
  12.         return NULL;
  13.     }

  14.     ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len);
获取主机名, 将其最下化之后存入cycle->hostname字段.

接下来的代码就是关于模块配置上下文的创建, 配置文件的解析, 配置上下文的初始化.
过程见http://blog.chinaunix.net/uid-22577711-id-4410347.html

点击(此处)折叠或打开

  1. if (ngx_create_paths(cycle, ccf->user) != NGX_OK) {
  2.         goto failed;
  3.     }
创建一些模块所需的目录. 如scgi_temp目录等

点击(此处)折叠或打开

  1. if (ngx_log_open_default(cycle) != NGX_OK) {
  2.         goto failed;
  3.     }
将默认的日志文件即log/nginx.log加入要打开的文件列表, 并初始化cycle->new_log的log_level和file字段.

点击(此处)折叠或打开

  1. part = &cycle->open_files.part;
  2.     file = part->elts;

  3.     for (i = 0; /* void */ ; i++) {

  4.         if (i >= part->nelts) {
  5.             if (part->next == NULL) {
  6.                 break;
  7.             }
  8.             part = part->next;
  9.             file = part->elts;
  10.             i = 0;
  11.         }

  12.         if (file[i].name.len == 0) {
  13.             continue;
  14.         }

  15.         file[i].fd = ngx_open_file(file[i].name.data,
  16.                                    NGX_FILE_APPEND,
  17.                                    NGX_FILE_CREATE_OR_OPEN,
  18.                                    NGX_FILE_DEFAULT_ACCESS);

  19.         ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0,
  20.                        "log: %p %d \"%s\"",
  21.                        &file[i], file[i].fd, file[i].name.data);

  22.         if (file[i].fd == NGX_INVALID_FILE) {
  23.             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
  24.                           ngx_open_file_n " \"%s\" failed",
  25.                           file[i].name.data);
  26.             goto failed;
  27.         }
  28. #if !(NGX_WIN32)
  29.         if (fcntl(file[i].fd, F_SETFD, FD_CLOEXEC) == -1) {
  30.             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
  31.                           "fcntl(FD_CLOEXEC) \"%s\" failed",
  32.                           file[i].name.data);
  33.             goto failed;
  34.         }
  35. #endif
  36.     }
打开列表中所有的文件并保存相应的文件描述符. 设置描述符的FD_CLOEXEC标志.

点击(此处)折叠或打开

  1. cycle->log = &cycle->new_log;
  2. pool->log = &cycle->new_log;
使用新的log日志文件, 即默认的nginx.log

下面跳到579行

点击(此处)折叠或打开

  1. if (ngx_open_listening_sockets(cycle) != NGX_OK) {
  2.         goto failed;
  3.     }
打开保存在cycle->listening数组中需要监听的地址及端口.  这些地址端口信息在解析配置文件时加入.
socket, bind, listen, 并且对套接字设置了地址重用选项等。

点击(此处)折叠或打开

  1. if (!ngx_test_config) {
  2.         ngx_configure_listening_sockets(cycle);
  3.     }
对所有的套接字根据配置文件中的设置进行配置. 如接收和发送缓冲区大小.

点击(此处)折叠或打开

  1. for (i = 0; ngx_modules[i]; i++) {
  2.         if (ngx_modules[i]->init_module) {
  3.             if (ngx_modules[i]->init_module(cycle) != NGX_OK) {
  4.                 /* fatal */
  5.                 exit(1);
  6.             }
  7.         }
  8.     }
调用所有模块的init_module方法初始化模块. 几乎没有模块提供这个方法. ngx_event_core_module提供.

点击(此处)折叠或打开

  1. ngx_destroy_pool(conf.temp_pool);
  2. if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) {

  3.         /*
  4.          * perl_destruct() frees environ, if it is not the same as it was at
  5.          * perl_construct() time, therefore we save the previous cycle
  6.          * environment before ngx_conf_parse() where it will be changed.
  7.          */

  8.         env = environ;
  9.         environ = senv;

  10.         ngx_destroy_pool(old_cycle->pool);
  11.         cycle->old_cycle = NULL;

  12.         environ = env;

  13.         return cycle;
  14.     }
释放掉不再使用的内存池. 返回新创建的已经初始化好的ngx_cycle_t结构.

简而言之该函数所做的事情就是更新时区及时间缓存, 创建ngx_cycle_t结构并初始化一些字段, 解析配置文件, 设置好所有模块的配置上下文. 创建目录, 打开文,  监听端口.
阅读(3540) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~