Nginx啟動過程流程圖
下面首先給出Nginx啟動過程的流程圖:

ngx_cycle_t結構體
Nginx的啟動初始化在src/core/nginx.c的main函數中完成,當然main函數是整個Nginx的入口,除了完成啟動初始化任務以外,也必定是所有功能模塊的入口之處。Nginx的初始化工作主要圍繞一個類型為ngx_cycle_t類型的全局變量(cycle)展開。
ngx_cycle_t結構體類型:
typedef struct ngx_cycle_s ngx_cycle_t;
struct ngx_cycle_s {
void ****conf_ctx; //配置上下文數組(含所有模塊)
ngx_pool_t *pool; //內存池
ngx_log_t *log; //日志
ngx_log_t new_log;
ngx_connection_t **files; //連接文件
ngx_connection_t *free_connections; //空閑連接
ngx_uint_t free_connection_n; //空閑連接個數
ngx_queue_t reusable_connections_queue; //再利用連接隊列
ngx_array_t listening; //監聽數組
ngx_array_t pathes; //路徑數組
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; //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; //主機名
};
main函數源代碼分析
下面具體看一下main函數為Nginx的啟動過程做了哪些初始化。
//Nginx中main函數,涵蓋了Nginx啟動過程
int ngx_cdecl
main(int argc, char *const *argv)
{
ngx_int_t i;
ngx_log_t *log;
ngx_cycle_t *cycle, init_cycle;
ngx_core_conf_t *ccf;
ngx_debug_init();
if (ngx_strerror_init() != NGX_OK) {
return 1;
}
//對參數選項進行處理
if (ngx_get_options(argc, argv) != NGX_OK) {
return 1;
}
//根據參數選項采取相應動作,比如:顯示版本、測試配置等功能
if (ngx_show_version) {
ngx_write_stderr("nginx version: " NGINX_VER NGX_LINEFEED);
if (ngx_show_help) {
ngx_write_stderr(
"Usage: nginx [-?hvVtq] [-s signal] [-c filename] "
"[-p prefix] [-g directives]" NGX_LINEFEED
NGX_LINEFEED
"Options:" NGX_LINEFEED
" -?,-h : this help" NGX_LINEFEED
" -v : show version and exit" NGX_LINEFEED
" -V : show version and configure options then exit"
NGX_LINEFEED
" -t : test configuration and exit" NGX_LINEFEED
" -q : suppress non-error messages "
"during configuration testing" NGX_LINEFEED
" -s signal : send signal to a master process: "
"stop, quit, reopen, reload" NGX_LINEFEED
#ifdef NGX_PREFIX
" -p prefix : set prefix path (default: "
NGX_PREFIX ")" NGX_LINEFEED
#else
" -p prefix : set prefix path (default: NONE)" NGX_LINEFEED
#endif
" -c filename : set configuration file (default: "
NGX_CONF_PATH ")" NGX_LINEFEED
" -g directives : set global directives out of configuration "
"file" NGX_LINEFEED NGX_LINEFEED
);
}
if (ngx_show_configure) {
ngx_write_stderr(
#ifdef NGX_COMPILER
"built by " NGX_COMPILER NGX_LINEFEED
#endif
#if (NGX_SSL)
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
"TLS SNI support enabled" NGX_LINEFEED
#else
"TLS SNI support disabled" NGX_LINEFEED
#endif
#endif
"configure arguments:" NGX_CONFIGURE NGX_LINEFEED);
}
if (!ngx_test_config) {
return 0;
}
}
/* TODO */ ngx_max_sockets = -1;
//初始化並更新時間
ngx_time_init();
#if (NGX_PCRE)
ngx_regex_init();
#endif
ngx_pid = ngx_getpid();
//初始化日志
log = ngx_log_init(ngx_prefix);
if (log == NULL) {
return 1;
}
/* STUB */
#if (NGX_OPENSSL)
ngx_ssl_init(log);
#endif
/*
* init_cycle->log is required for signal handlers and
* ngx_process_options()
*/
//清零全局變量ngx_cycle,並分配內存池
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_os_argv、ngx_argc以及ngx_argv這幾個全局的變量中。這算是一個備份存儲,方便以后master進程做熱代碼替換之用。
if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) {
return 1;
}
//用Nginx運行是攜帶的目錄參數初始化init_cycle
if (ngx_process_options(&init_cycle) != NGX_OK) {
return 1;
}
//完成操作系統的一些信息提取,信息會被保存到一些全局變量中
if (ngx_os_init(log) != NGX_OK) {
return 1;
}
/*
* ngx_crc32_table_init() requires ngx_cacheline_size set in ngx_os_init()
*/
//初始化一個做循環冗余校驗的表,由此可以看出后續的循環冗余校驗將采用高效的查表法
if (ngx_crc32_table_init() != NGX_OK) {
return 1;
}
//通過環境變量NGINX完成socket的繼承,繼承來的socket將會放到init_cycle的listening數組中。同時可以讀取master進程傳遞的平滑升級信息等等
if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) {
return 1;
}
//初始化所有模塊的index信息,即對所有模塊進行編號
//ngx_modules數卻是在自動編譯的時候生成的,位於objs/ngx_modules.c文件中
ngx_max_module = 0;
for (i = 0; ngx_modules[i]; i++) {
ngx_modules[i]->index = ngx_max_module++;
}
//完成很多信息的初始化工作
cycle = ngx_init_cycle(&init_cycle);
if (cycle == NULL) {
if (ngx_test_config) {
ngx_log_stderr(0, "configuration file %s test failed",
init_cycle.conf_file.data);
}
return 1;
}
if (ngx_test_config) {
if (!ngx_quiet_mode) {
ngx_log_stderr(0, "configuration file %s test is successful",
cycle->conf_file.data);
}
return 0;
}
//若有信號
if (ngx_signal) {
return ngx_signal_process(cycle, ngx_signal);
}
ngx_os_status(cycle->log);
ngx_cycle = cycle;
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
//這個地方需要解釋下
//ccf->master是從配置文件中解析master_process配置項所得的值,初始化為NGX_CONF_UNSET(-1),在配置項中,如果flag類型的配置項master_process被設置為on,則其值為1,如果為off,則其值為0
//ngx_process為全局變量,用於記錄要采用的工作模式,未被初始化,因此初始值是0(uint型全局變量會被系統默認初始化為0)
//相關宏定義如下
//#define NGX_PROCESS_SINGLE 0
//#define NGX_PROCESS_MASTER 1
//#define NGX_PROCESS_SIGNALLER 2
//#define NGX_PROCESS_WORKER 3
//#define NGX_PROCESS_HELPER 4
//因此,下面的if判斷語句的含義就是:用來處理一種特殊情況,即如果在配置項中未設置master_process配置項或者是設置為打開,ngx_process未被設置,采用默認值0,這個時候要采用master工作模式。因為master_process優先級高,且nginx默認采用master模式
///如果在配置項中設置master_process為off,那么if依據不會執行。最終nginx工作模式取決於ngx_proces的初值0,即采用單進程模式
if (ccf->master && ngx_process == NGX_PROCESS_SINGLE) {
ngx_process = NGX_PROCESS_MASTER;
}
#if !(NGX_WIN32)
//初始化信號;主要完成信號處理程序的注冊
if (ngx_init_signals(cycle->log) != NGX_OK) {
return 1;
}
//若無繼承sockets,且設置了守護進程表示,則創建守護進程
if (!ngx_inherited && ccf->daemon) {
if (ngx_daemon(cycle->log) != NGX_OK) {
return 1;
}
ngx_daemonized = 1;
}
if (ngx_inherited) {
ngx_daemonized = 1;
}
#endif
//創建進程記錄文件;(非NGX_PROCESS_MASTER=1進程,不創建該文件)
if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) {
return 1;
}
if (cycle->log->file->fd != ngx_stderr) {
if (ngx_set_stderr(cycle->log->file->fd) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
ngx_set_stderr_n " failed");
return 1;
}
}
if (log->file->fd != ngx_stderr) {
if (ngx_close_file(log->file->fd) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
ngx_close_file_n " built-in log failed");
}
}
ngx_use_stderr = 0;
//進入進程主循環
//單進程方式運行Nginx
if (ngx_process == NGX_PROCESS_SINGLE) {
ngx_single_process_cycle(cycle);
} else {
//以master多進程方式運行Nginx
ngx_master_process_cycle(cycle);
}
return 0;
}
關於master進程和worker進程的工作原理,參考:
http://blog.csdn.net/xiajun07061225/article/details/9241179
下面分析初始化過程中比較重要的一個函數ngx_init_cycle()。
cycle就是周期的意思,對應着一次啟動過程。也就是說,不論發生了上節介紹的三種啟動方式的哪一種,nginx都會創建一個新的cycle與這次啟動對應。
ngx_init_cycle提供的是配置解析接口。接口是一個切入點,通過少量代碼提供一個完整功能的調用。配置解析接口分為兩個階段,一個是准備階段,另一個就是真正開始調用配置解析。其核心代碼如下:
ngx_cycle_t *
ngx_init_cycle(ngx_cycle_t *old_cycle)
{
void *rv;
char **senv, **env;
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;
//創建內存池
pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
if (pool == NULL) {
return NULL;
}
pool->log = log;
//在內存池上分配一個ngx_cycle_t對象
cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t));
if (cycle == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
cycle->pool = pool;
cycle->log = log;
cycle->new_log.log_level = NGX_LOG_ERR;
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;
}
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 (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;
}
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數組(存儲監聽端口和相關參數ngx_listening_t類型的動態數組)
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;
ngx_queue_init(&cycle->reusable_connections_queue);
//初始化conf_ctx指針數組(保存所有模塊存儲配置項結構體的指針)
cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));
if (cycle->conf_ctx == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
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);
for (i = 0; ngx_modules[i]; i++) {
//非核心模塊跳過
if (ngx_modules[i]->type != NGX_CORE_MODULE) {
continue;
}
module = ngx_modules[i]->ctx;
//調用所有核心模塊的create_conf方法,構造用於存儲配置項的結構體
//那么非核心模塊怎么辦呢?其實這些模塊大多從屬於一個核心模塊,如每個http模塊都由ngx_http_module管理,這樣ngx_http_module在解析自己感興趣的配置項時,將會調用所有http模塊約定的方法來創建存儲配置項的結構體
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));
/* 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);
}
//調用所有核心模塊的init_conf方法,這一步驟的目的在於讓所有核心模塊在解析玩配置項后可以做綜合性處理
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;
}
}
}
if (ngx_process == NGX_PROCESS_SIGNALLER) {
return cycle;
}
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
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);
}
}
if (ngx_test_lockfile(cycle->lock_file.data, log) != NGX_OK) {
goto failed;
}
if (ngx_create_paths(cycle, ccf->user) != NGX_OK) {
goto failed;
}
if (cycle->new_log.file == NULL) {
cycle->new_log.file = ngx_conf_open_file(cycle, &error_log);
if (cycle->new_log.file == NULL) {
goto failed;
}
}
//創建目錄、打開文件、初始化共享內存等進程間通信方式
/* open the new 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
}
cycle->log = &cycle->new_log;
pool->log = &cycle->new_log;
/* create 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].shm.addr = oshm_zone[n].shm.addr;
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;
}
if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) {
goto failed;
}
if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) {
goto failed;
}
if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) {
goto failed;
}
shm_zone_found:
continue;
}
/* handle the listening sockets */
//打開從配置文件中讀取到的監聽端口
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 (ngx_cmp_sockaddr(nls[n].sockaddr, ls[i].sockaddr) == NGX_OK)
{
nls[n].fd = ls[i].fd;
nls[n].previous = &ls[i];
ls[i].remain = 1;
if (ls[n].backlog != nls[i].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[n].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
break;
}
}
if (nls[n].fd == -1) {
nls[n].open = 1;
}
}
} 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);
}
/* commit the new cycle configuration */
if (!ngx_use_stderr && cycle->log->file->fd != ngx_stderr) {
if (ngx_set_stderr(cycle->log->file->fd) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
ngx_set_stderr_n " failed");
}
}
pool->log = cycle->log;
//調用所有模塊的init_module方法
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);
}
}
}
return NULL;
}
轉載請出名出處:http://blog.csdn.net/xiajun07061225/article/details/9309273
