ngx_cycle_t 是nginx中的核心数据结构. 主框架代码围绕这个数据结构来展开.
ngx_init_cycle函数创建并初始化ngx_cycle_t结构, 并且初始化nginx的模块.
下面以第一次启动nginx并且是以master方式运行. 来看ngx_init_cycle函数所做的事情.
-
ngx_timezone_update();
-
ngx_time_update();
更新时区. 从其实现方式来看, 在linux中, 通过调用strftime可以达到更新时区的目的, strftime会调用tzset来读取存储在/etc/localtime中的时区信息
更新时区之后, 调用ngx_time_update来更新缓存的时间. 为了减少调用获取时间的函数的次数, nginx在一定的时间精度内将时间缓存起来. 获取时间只需要一次内存访问即可.
-
pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
-
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函数中初始化的. 代码就不贴出来了.
-
n = old_cycle->paths.nelts ? old_cycle->paths.nelts : 10;
-
-
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;
初始化动态数组cycle->paths, 预留10个元素的内存空间. 等价于 ngx_array_init(&cycle->paths, pool, n, sizeof(ngx_path_t *)).
关于nginx的动态数组见
http://blog.chinaunix.net/uid-22577711-id-4389317.html
-
if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t))
-
!= NGX_OK)
初始化链表cycle->open_files, 预留空间为20.
-
if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t))
-
!= NGX_OK)
初始化链表cycle->shared_memory, 预留空间为1.
-
n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10;
-
-
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;
初始化动态数组cycle->listening, 预留空间为10.
-
ngx_queue_init(&cycle->reusable_connections_queue);
初始化队列cycle->reusable_connections_queue.
-
cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));
分配用于保存所有模块配置上下文指针的数组.
-
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;
-
}
-
-
ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len);
获取主机名, 将其最下化之后存入cycle->hostname字段.
接下来的代码就是关于模块配置上下文的创建, 配置文件的解析, 配置上下文的初始化.
过程见
http://blog.chinaunix.net/uid-22577711-id-4410347.html
-
if (ngx_create_paths(cycle, ccf->user) != NGX_OK) {
-
goto failed;
-
}
创建一些模块所需的目录. 如scgi_temp目录等
-
if (ngx_log_open_default(cycle) != NGX_OK) {
-
goto failed;
-
}
将默认的日志文件即log/nginx.log加入要打开的文件列表, 并初始化cycle->new_log的log_level和file字段.
-
part = &cycle->open_files.part;
-
file = part->elts;
-
-
for (i = 0; /* void */ ; i++) {
-
-
if (i >= part->nelts) {
-
if (part->next == NULL) {
-
break;
-
}
-
part = part->next;
-
file = part->elts;
-
i = 0;
-
}
-
-
if (file[i].name.len == 0) {
-
continue;
-
}
-
-
file[i].fd = ngx_open_file(file[i].name.data,
-
NGX_FILE_APPEND,
-
NGX_FILE_CREATE_OR_OPEN,
-
NGX_FILE_DEFAULT_ACCESS);
-
-
ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0,
-
"log: %p %d \"%s\"",
-
&file[i], file[i].fd, file[i].name.data);
-
-
if (file[i].fd == NGX_INVALID_FILE) {
-
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
-
ngx_open_file_n " \"%s\" failed",
-
file[i].name.data);
-
goto failed;
-
}
-
#if !(NGX_WIN32)
-
if (fcntl(file[i].fd, F_SETFD, FD_CLOEXEC) == -1) {
-
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
-
"fcntl(FD_CLOEXEC) \"%s\" failed",
-
file[i].name.data);
-
goto failed;
-
}
-
#endif
-
}
打开列表中所有的文件并保存相应的文件描述符. 设置描述符的FD_CLOEXEC标志.
-
cycle->log = &cycle->new_log;
-
pool->log = &cycle->new_log;
使用新的log日志文件, 即默认的nginx.log
下面跳到579行
-
if (ngx_open_listening_sockets(cycle) != NGX_OK) {
-
goto failed;
-
}
打开保存在cycle->listening数组中需要监听的地址及端口. 这些地址端口信息在解析配置文件时加入.
socket, bind, listen, 并且对套接字设置了地址重用选项等。
-
if (!ngx_test_config) {
-
ngx_configure_listening_sockets(cycle);
-
}
对所有的套接字根据配置文件中的设置进行配置. 如接收和发送缓冲区大小.
-
for (i = 0; ngx_modules[i]; i++) {
-
if (ngx_modules[i]->init_module) {
-
if (ngx_modules[i]->init_module(cycle) != NGX_OK) {
-
/* fatal */
-
exit(1);
-
}
-
}
-
}
调用所有模块的init_module方法初始化模块. 几乎没有模块提供这个方法. ngx_event_core_module提供.
-
ngx_destroy_pool(conf.temp_pool);
-
if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) {
-
-
/*
-
* perl_destruct() frees environ, if it is not the same as it was at
-
* perl_construct() time, therefore we save the previous cycle
-
* environment before ngx_conf_parse() where it will be changed.
-
*/
-
-
env = environ;
-
environ = senv;
-
-
ngx_destroy_pool(old_cycle->pool);
-
cycle->old_cycle = NULL;
-
-
environ = env;
-
-
return cycle;
-
}
释放掉不再使用的内存池. 返回新创建的已经初始化好的ngx_cycle_t结构.
简而言之该函数所做的事情就是更新时区及时间缓存, 创建ngx_cycle_t结构并初始化一些字段, 解析配置文件, 设置好所有模块的配置上下文. 创建目录, 打开文, 监听端口.
阅读(3664) | 评论(0) | 转发(0) |