Nginx的大部分初始化工作主要围绕一个类型为ngx_cycle_t类型的全局变量(cycle)展开。本文主要讲解cycle的数据结构以及初始化过程中干了什么事情。
cycle的初始化过程在/src/core/cycle.c文件中。
cycle是Nginx贯穿全局的一个全局变量。阅读Nginx的源码必须得先搞清楚cycle全局变量的初始化过程。
/** * Nginx全局变量cycle */ struct ngx_cycle_s { void ****conf_ctx; /* 配置文件 上下文的数组,每个模块的配置信息*/ ngx_pool_t *pool; /* 内存池地址 */ ngx_log_t *log; /* 日志 */ ngx_log_t new_log; ngx_uint_t log_use_stderr; /* unsigned log_use_stderr:1; */ ngx_connection_t **files; /* 连接文件句柄 */ ngx_connection_t *free_connections; /* 空闲连接 */ ngx_uint_t free_connection_n;/* 空闲连接个数 */ ngx_module_t **modules; /* 模块数组 */ ngx_uint_t modules_n; /* 模块个数 */ ngx_uint_t modules_used; /* unsigned modules_used:1; */ ngx_queue_t reusable_connections_queue; ngx_array_t listening; /* 监听数组 */ ngx_array_t paths; /* 路径数组 */ ngx_array_t config_dump; ngx_list_t open_files; /* 打开的文件 */ ngx_list_t shared_memory;/* 共享内存链表*/ ngx_uint_t connection_n; /* 连接的个数*/ ngx_uint_t files_n; /* 打开文件的个数 */ ngx_connection_t *connections; /* 连接事件*/ ngx_event_t *read_events; /* 读取事件*/ ngx_event_t *write_events; /* 写入事件*/ ngx_cycle_t *old_cycle; ngx_str_t conf_file; /* 配置文件 */ ngx_str_t conf_param; /* 配置参数 */ ngx_str_t conf_prefix; /* 配置文件前缀*/ ngx_str_t prefix; /* 前缀*/ ngx_str_t lock_file; /* 锁文件*/ ngx_str_t hostname; /* 主机名称*/ };
ngx_code_conf_t的数据结构主要用于装在Nginx的nginx.conf的核心配置文件的参数。后面我们会具体讲解配置文件nginx.conf的解析过程以及和模块。
/** * 核心配置文件信息 * 对应nginx.conf的 * #user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; */ typedef struct { ngx_flag_t daemon; ngx_flag_t master; ngx_msec_t timer_resolution; ngx_int_t worker_processes; ngx_int_t debug_points; ngx_int_t rlimit_nofile; off_t rlimit_core; int priority; ngx_uint_t cpu_affinity_auto; ngx_uint_t cpu_affinity_n; ngx_cpuset_t *cpu_affinity; char *username; ngx_uid_t user; ngx_gid_t group; ngx_str_t working_directory; ngx_str_t lock_file; ngx_str_t pid; ngx_str_t oldpid; ngx_array_t env; char **environment; } ngx_core_conf_t;
后续所有的内存都会被分配到这个内存池上面。
/* 创建一块内存 */ pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log); if (pool == NULL) { return NULL; } pool->log = log; 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/ */ 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
/* Nginx路径拷贝 */ 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; }
/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); 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; }
/* 路径信息 */ 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; if (ngx_array_init(&cycle->config_dump, pool, 1, sizeof(ngx_conf_dump_t)) != NGX_OK) { ngx_destroy_pool(pool); return NULL; }
/* 初始化打开的文件句柄 */ 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; } if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t)) != NGX_OK) { ngx_destroy_pool(pool); return NULL; }
/* 初始化shared_memory链表 */ 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; } if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t)) != NGX_OK) { ngx_destroy_pool(pool); return NULL; }
/* 初始化listening */ 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;
1. 主要初始化cycle->modules
2. 创建核心配置结构,Nginx的核心配置会放到ngx_core_conf_t *ccf数据结构上
3. 初始化核心配置结构ngx_core_conf_t *
/* 创建模块以及创建模块的配置信息 */ if (ngx_cycle_modules(cycle) != NGX_OK) { ngx_destroy_pool(pool); return NULL; } /* * 核心模块的配置文件创建 * 配置创建调用nginx.c 中的 ngx_core_module_create_conf * */ for (i = 0; cycle->modules[i]; i++) { if (cycle->modules[i]->type != NGX_CORE_MODULE) { continue; } module = cycle->modules[i]->ctx; if (module->create_conf) { rv = module->create_conf(cycle); //模块回调函数,创建模块的配置信息 if (rv == NULL) { ngx_destroy_pool(pool); return NULL; } cycle->conf_ctx[cycle->modules[i]->index] = rv; //配置文件复制 } }
/* 获取核心配置文件的数据结构 ngx_core_conf_t */ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
配置文件解析会在下章中详细解读。
/* 解析配置文件 */ ngx_memzero(&conf, sizeof(ngx_conf_t)); /* 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也主要用于解析配置文件的临时变量 */ 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 /* 解析命令行中的配置参数;例如:nginx -t -c /usr/local/nginx/conf/nginx.conf */ if (ngx_conf_param(&conf) != NGX_CONF_OK) { environ = senv; ngx_destroy_cycle_pools(&conf); return NULL; } /* 解析配置文件/usr/local/nginx/conf/nginx.conf 信息 */ 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); }
Nginx将PID写入文件内,/usr/local/nginx-1.4.7/nginx.pid,后续对Nginx进行重启、停止、信号操作就可以使用这个PID了。
/* 创建pid文件,/usr/local/nginx-1.4.7/nginx.pid*/ if (ngx_test_config) { if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) { goto failed; } } else if (!ngx_is_init_cycle(old_cycle)) { /* * we do not create the pid file in the first ngx_init_cycle() call * because we need to write the demonized process pid */ old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx, ngx_core_module); if (ccf->pid.len != old_ccf->pid.len || ngx_strcmp(ccf->pid.data, old_ccf->pid.data) != 0) { /* new pid file name */ if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) { goto failed; } ngx_delete_pidfile(old_cycle); } }
cycle->open_file主要是在ngx_conf_open_file这个方法里面放入文件路径,然后下面去打开文件。
主要是日志文件和配置文件。
/* 打开日志,并调用ngx_conf_open_file方法,会将打开的文件放到cycle->open_files链表中 主要是日志文件和配置文件*/ if (ngx_log_open_default(cycle) != NGX_OK) { goto failed; }
/* 遍历cycle->open_files链表中的文件,并打开 */ 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 }
新旧shared_memory链表的比较,相同的共享内存保留,旧的不同的共享内存被释放,新的被创建
/* 创建共享内存并初始化 */ part = &cycle->shared_memory.part; shm_zone = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; shm_zone = part->elts; i = 0; } if (shm_zone[i].shm.size == 0) { ngx_log_error(NGX_LOG_EMERG, log, 0, "zero size shared memory zone \"%V\"", &shm_zone[i].shm.name); goto failed; } shm_zone[i].shm.log = cycle->log; opart = &old_cycle->shared_memory.part; oshm_zone = opart->elts; for (n = 0; /* void */ ; n++) { if (n >= opart->nelts) { if (opart->next == NULL) { break; } opart = opart->next; oshm_zone = opart->elts; n = 0; } if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) { continue; } if (ngx_strncmp(shm_zone[i].shm.name.data, oshm_zone[n].shm.name.data, shm_zone[i].shm.name.len) != 0) { continue; } if (shm_zone[i].tag == oshm_zone[n].tag && shm_zone[i].shm.size == oshm_zone[n].shm.size && !shm_zone[i].noreuse) { shm_zone[i].shm.addr = oshm_zone[n].shm.addr; #if (NGX_WIN32) shm_zone[i].shm.handle = oshm_zone[n].shm.handle; #endif if (shm_zone[i].init(&shm_zone[i], oshm_zone[n].data) != NGX_OK) { goto failed; } goto shm_zone_found; } ngx_shm_free(&oshm_zone[n].shm); break; }
/* handle the listening sockets */ /* 处理listening数组,并开始监听socket */ if (old_cycle->listening.nelts) { ls = old_cycle->listening.elts; for (i = 0; i < old_cycle->listening.nelts; i++) { ls[i].remain = 0; } nls = cycle->listening.elts; for (n = 0; n < cycle->listening.nelts; n++) { for (i = 0; i < old_cycle->listening.nelts; i++) { if (ls[i].ignore) { continue; } if (ls[i].remain) { continue; } if (ls[i].type != nls[n].type) { continue; } if (ngx_cmp_sockaddr(nls[n].sockaddr, nls[n].socklen, ls[i].sockaddr, ls[i].socklen, 1) == NGX_OK) { nls[n].fd = ls[i].fd; nls[n].previous = &ls[i]; ls[i].remain = 1; if (ls[i].backlog != nls[n].backlog) { nls[n].listen = 1; } #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) /* * FreeBSD, except the most recent versions, * could not remove accept filter */ nls[n].deferred_accept = ls[i].deferred_accept; if (ls[i].accept_filter && nls[n].accept_filter) { if (ngx_strcmp(ls[i].accept_filter, nls[n].accept_filter) != 0) { nls[n].delete_deferred = 1; nls[n].add_deferred = 1; } } else if (ls[i].accept_filter) { nls[n].delete_deferred = 1; } else if (nls[n].accept_filter) { nls[n].add_deferred = 1; } #endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) if (ls[i].deferred_accept && !nls[n].deferred_accept) { nls[n].delete_deferred = 1; } else if (ls[i].deferred_accept != nls[n].deferred_accept) { nls[n].add_deferred = 1; } #endif #if (NGX_HAVE_REUSEPORT) if (nls[n].reuseport && !ls[i].reuseport) { nls[n].add_reuseport = 1; } #endif break; } } if (nls[n].fd == (ngx_socket_t) -1) { nls[n].open = 1; #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) if (nls[n].accept_filter) { nls[n].add_deferred = 1; } #endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) if (nls[n].deferred_accept) { nls[n].add_deferred = 1; } #endif } } } else { ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { ls[i].open = 1; #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) if (ls[i].accept_filter) { ls[i].add_deferred = 1; } #endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) if (ls[i].deferred_accept) { ls[i].add_deferred = 1; } #endif } } if (ngx_open_listening_sockets(cycle) != NGX_OK) { goto failed; } if (!ngx_test_config) { ngx_configure_listening_sockets(cycle); }
1. 释放多余的共享内存;
2. 关闭多余的侦听sockets;
3. 关闭多余的打开文件
/* close and delete stuff that lefts from an old cycle */ /* free the unnecessary shared memory */ /* 关闭或删除残留在old_cycle中的资源 释放多余的共享内存;关闭多余的侦听sockets;关闭多余的打开文件*/ opart = &old_cycle->shared_memory.part; oshm_zone = opart->elts; for (i = 0; /* void */ ; i++) { if (i >= opart->nelts) { if (opart->next == NULL) { goto old_shm_zone_done; } opart = opart->next; oshm_zone = opart->elts; i = 0; } part = &cycle->shared_memory.part; shm_zone = part->elts; for (n = 0; /* void */ ; n++) { if (n >= part->nelts) { if (part->next == NULL) { break; } part = part->next; shm_zone = part->elts; n = 0; } if (oshm_zone[i].shm.name.len == shm_zone[n].shm.name.len && ngx_strncmp(oshm_zone[i].shm.name.data, shm_zone[n].shm.name.data, oshm_zone[i].shm.name.len) == 0) { goto live_shm_zone; } } ngx_shm_free(&oshm_zone[i].shm);