Ubuntu 下 nginx-1.24.0 源碼分析 - ngx_init_cycle 函數

nei聲明src/core/ngx_cycle.h

ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle);

實現src/core/ngx_cycle.c

ngx_cycle_t *
ngx_init_cycle(ngx_cycle_t *old_cycle)
{void                *rv;char               **senv;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;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.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->error_log.len = old_cycle->error_log.len;cycle->error_log.data = ngx_pnalloc(pool, old_cycle->error_log.len + 1);if (cycle->error_log.data == NULL) {ngx_destroy_pool(pool);return NULL;}ngx_cpystrn(cycle->error_log.data, old_cycle->error_log.data,old_cycle->error_log.len + 1);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;if (ngx_array_init(&cycle->paths, pool, n, sizeof(ngx_path_t *))!= NGX_OK){ngx_destroy_pool(pool);return NULL;}ngx_memzero(cycle->paths.elts, n * sizeof(ngx_path_t *));if (ngx_array_init(&cycle->config_dump, pool, 1, sizeof(ngx_conf_dump_t))!= NGX_OK){ngx_destroy_pool(pool);return NULL;}ngx_rbtree_init(&cycle->config_dump_rbtree, &cycle->config_dump_sentinel,ngx_str_rbtree_insert_value);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;}n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10;if (ngx_array_init(&cycle->listening, pool, n, sizeof(ngx_listening_t))!= NGX_OK){ngx_destroy_pool(pool);return NULL;}ngx_memzero(cycle->listening.elts, n * sizeof(ngx_listening_t));ngx_queue_init(&cycle->reusable_connections_queue);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);if (ngx_cycle_modules(cycle) != NGX_OK) {ngx_destroy_pool(pool);return NULL;}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;}}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 0log->log_level = NGX_LOG_DEBUG_ALL;
#endifif (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; cycle->modules[i]; i++) {if (cycle->modules[i]->type != NGX_CORE_MODULE) {continue;}module = cycle->modules[i]->ctx;if (module->init_conf) {if (module->init_conf(cycle,cycle->conf_ctx[cycle->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 (ngx_log_open_default(cycle) != NGX_OK) {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].noreuse){shm_zone[i].shm.addr = oshm_zone[n].shm.addr;
#if (NGX_WIN32)shm_zone[i].shm.handle = oshm_zone[n].shm.handle;
#endifif (shm_zone[i].init(&shm_zone[i], oshm_zone[n].data)!= NGX_OK){goto failed;}goto shm_zone_found;}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 (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].inherited = ls[i].inherited;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;}
#endifbreak;}}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);}/* commit the new cycle configuration */if (!ngx_use_stderr) {(void) ngx_log_redirect_stderr(cycle);}pool->log = cycle->log;if (ngx_init_modules(cycle) != NGX_OK) {/* fatal */exit(1);}/* close and delete stuff that lefts from an old cycle *//* free the unnecessary shared memory */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) {continue;}if (ngx_strncmp(oshm_zone[i].shm.name.data,shm_zone[n].shm.name.data,oshm_zone[i].shm.name.len)!= 0){continue;}if (oshm_zone[i].tag == shm_zone[n].tag&& oshm_zone[i].shm.size == shm_zone[n].shm.size&& !oshm_zone[i].noreuse){goto live_shm_zone;}break;}ngx_shm_free(&oshm_zone[i].shm);live_shm_zone:continue;}old_shm_zone_done:/* close the unnecessary listening sockets */ls = old_cycle->listening.elts;for (i = 0; i < old_cycle->listening.nelts; i++) {if (ls[i].remain || ls[i].fd == (ngx_socket_t) -1) {continue;}if (ngx_close_socket(ls[i].fd) == -1) {ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,ngx_close_socket_n " listening socket on %V failed",&ls[i].addr_text);}#if (NGX_HAVE_UNIX_DOMAIN)if (ls[i].sockaddr->sa_family == AF_UNIX) {u_char  *name;name = ls[i].addr_text.data + sizeof("unix:") - 1;ngx_log_error(NGX_LOG_WARN, cycle->log, 0,"deleting socket %s", name);if (ngx_delete_file(name) == NGX_FILE_ERROR) {ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,ngx_delete_file_n " %s failed", name);}}#endif}/* close the unnecessary open files */part = &old_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].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) {continue;}if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,ngx_close_file_n " \"%s\" failed",file[i].name.data);}}ngx_destroy_pool(conf.temp_pool);if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) {ngx_destroy_pool(old_cycle->pool);cycle->old_cycle = NULL;return cycle;}if (ngx_temp_pool == NULL) {ngx_temp_pool = ngx_create_pool(128, cycle->log);if (ngx_temp_pool == NULL) {ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,"could not create ngx_temp_pool");exit(1);}n = 10;if (ngx_array_init(&ngx_old_cycles, ngx_temp_pool, n,sizeof(ngx_cycle_t *))!= NGX_OK){exit(1);}ngx_memzero(ngx_old_cycles.elts, n * sizeof(ngx_cycle_t *));ngx_cleaner_event.handler = ngx_clean_old_cycles;ngx_cleaner_event.log = cycle->log;ngx_cleaner_event.data = &dumb;dumb.fd = (ngx_socket_t) -1;}ngx_temp_pool->log = cycle->log;old = ngx_array_push(&ngx_old_cycles);if (old == NULL) {exit(1);}*old = old_cycle;if (!ngx_cleaner_event.timer_set) {ngx_add_timer(&ngx_cleaner_event, 30000);ngx_cleaner_event.timer_set = 1;}return cycle;failed:if (!ngx_is_init_cycle(old_cycle)) {old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx,ngx_core_module);if (old_ccf->environment) {environ = old_ccf->environment;}}/* rollback the new cycle configuration */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].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) {continue;}if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,ngx_close_file_n " \"%s\" failed",file[i].name.data);}}/* free the newly created 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.addr == NULL) {continue;}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){goto old_shm_zone_found;}break;}ngx_shm_free(&shm_zone[i].shm);old_shm_zone_found:continue;}if (ngx_test_config) {ngx_destroy_cycle_pools(&conf);return NULL;}ls = cycle->listening.elts;for (i = 0; i < cycle->listening.nelts; i++) {if (ls[i].fd == (ngx_socket_t) -1 || !ls[i].open) {continue;}if (ngx_close_socket(ls[i].fd) == -1) {ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,ngx_close_socket_n " %V failed",&ls[i].addr_text);}}ngx_destroy_cycle_pools(&conf);return NULL;
}

ngx_init_cycle?是 Nginx 核心模塊中的一個關鍵函數,
負責初始化 Nginx 的運行環境。
它基于傳入的舊周期(old_cycle)創建一個新的周期(cycle),
并完成一系列復雜的初始化工作,
包括配置文件解析、共享內存分配、監聽套接字設置等。


函數簽名

ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle)

作用

  • 接收一個指向舊周期(old_cycle)的指針。

  • 返回一個新創建的周期(cycle)指針,表示初始化后的運行時環境。

  • 如果初始化失敗,返回?NULL

  • 新周期會繼承舊周期的部分信息(如路徑、配置文件路徑等),同時根據新的配置進行更新。


   ngx_timezone_update();/* force localtime update with a new timezone */tp = ngx_timeofday();tp->sec = 0;ngx_time_update();

ngx_timezone_update()更新進程的時區緩存
ngx_timeofday() 獲取當前時間緩存對象 tp。
tp->sec = 0 強制標記時間緩存為“已失效”。
ngx_time_update() 重新計算當前時間并更新緩存。

tp->sec = 0; 的作用是強制標記當前時間緩存為無效,從而確保在調用 ngx_time_update() 時會重新調用系統函數來獲取最新的時間戳。
如果沒有強制刷新時間緩存(即 tp->sec != 0),ngx_time_update() 可能不會真正調用系統函數,而是直接使用緩存值


   log = old_cycle->log;

?從舊的 Nginx 運行周期(old_cycle)中繼承日志對象(log),并將其賦值給當前的局部變量 log

新周期初始化時,尚未解析新的配置文件,無法確定新的日志路徑或級別。
若直接使用新配置的日志可能失敗(如路徑無效),導致錯誤信息無法記錄。
復用舊日志配置,新周期完全初始化前,確保初始化階段的日志記錄可靠。


   pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);if (pool == NULL) {return NULL;}pool->log = log;

創建一個內存池(memory pool),用于管理 Nginx 運行周期(cycle)中的內存分配

NGX_CYCLE_POOL_SIZE
這是一個宏定義,表示內存池的初始大小。

log?是一個指向日志對象的指針,用于記錄內存池操作中的錯誤或調試信息。


   cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t));if (cycle == NULL) {ngx_destroy_pool(pool);return NULL;}

從內存池分配一個新的?ngx_cycle_t?結構(核心運行時上下文)


   cycle->pool = pool;cycle->log = log;cycle->old_cycle = old_cycle;

?cycle->pool = pool;
關聯新內存池到新周期。
所有后續內存分配均通過此池進行,確保統一管理。

?cycle->log = log;
設置新周期的日志對象。
確保新周期的所有操作使用繼承的日志配置,直到新配置生效。

?cycle->old_cycle = old_cycle;
保存舊周期指針到新周期。
在平滑重啟或重新配置時,新周期需要訪問舊周期的資源(如監聽套接字、共享內存)。
資源復用:通過 old_cycle 復用舊資源(如 SO_REUSEPORT 套接字),實現零停機更新。
漸進式釋放:舊周期資源在新周期穩定后逐步清理,避免服務中斷。


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

復制配置文件前綴(conf_prefix

從舊周期復制?conf_prefix,用于定位配置文件
平滑重啟:保持配置路徑一致,避免重新解析路徑導致的延遲。

ngx_pstrdup


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

從舊周期復制?prefix(如?/usr/local/nginx/),用于解析相對路徑


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

繼承錯誤日志路徑:復制舊周期的錯誤日志文件路徑
日志連續性:初始化階段使用舊日志配置,避免日志記錄中斷
字符串安全性:通過?ngx_cpystrn?確保字符串以?\0?結尾


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

繼承命令行配置參數:復制通過?-g?參數傳遞的配置


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

確定 paths 數組的初始容量 n

若舊周期(old_cycle)存在路徑配置,則繼承其大小;否則預分配 10 個元素。

paths 用于存儲 Nginx 運行時路徑(如臨時文件目錄)。舊周期可能已包含路徑信息(如 client_body_temp_path),新周期需復用或初始化。

資源復用:繼承舊周期的容量,避免重復計算路徑數量。
預分配優化:默認值 10 是經驗值,平衡內存占用與擴容開銷。


    ngx_memzero(cycle->paths.elts, n * sizeof(ngx_path_t *));

將?paths?數組的前?n?個元素清零(初始化為?NULL

ngx_array_init?分配的內存未初始化,可能包含臟數據。路徑指針需顯式置空,避免后續誤判

確保數組初始狀態明確(所有元素為?NULL


    if (ngx_array_init(&cycle->config_dump, pool, 1, sizeof(ngx_conf_dump_t))!= NGX_OK){ngx_destroy_pool(pool);return NULL;}

初始化數組?config_dump,用于存儲配置轉儲條目

使用內存池?pool?分配內存,初始容量為 1,每個元素大小為?ngx_conf_dump_t

若初始化失敗(返回?NGX_ERROR),銷毀內存池并終止初始化。

Ubuntu 下 nginx-1.24.0 源碼分析 - ngx_conf_dump_t-CSDN博客


    ngx_rbtree_init(&cycle->config_dump_rbtree, &cycle->config_dump_sentinel,ngx_str_rbtree_insert_value);

初始化紅黑樹 config_dump_rbtree,用于快速查找和去重

根節點為 config_dump_rbtree,哨兵節點為 config_dump_sentinel
使用 ngx_str_rbtree_insert_value 作為插入回調,按字符串鍵排序。
?


Ubuntu 下 nginx-1.24.0 源碼分析 - ngx_rbtree_init-CSDN博客

Ubuntu 下 nginx-1.24.0 源碼分析 - ngx_str_rbtree_insert_value-CSDN博客

ngx_array_t config_dump

存儲配置條目

動態數組,存儲 ngx_conf_dump_t 結構體

ngx_rbtree_t config_dump_rbtree

索引配置條目,加速查找與去重

紅黑樹鍵值為配置名稱(ngx_str_t),節點數據指向 config_dump 數組素


? ? ? ? ? ? ? ??
?? ??? ?

ngx_conf_dump_t.name(配置塊名稱)作為紅黑樹的鍵,通過 ngx_str_rbtree_insert_value 回調按字符串排序。


功能分離:
數組存儲數據,紅黑樹管理索引,職責清晰。


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

open_files?存儲 nginx 運行時需持久打開的文件(如日志文件、共享內存文件)。

在平滑重啟或重新配置時,新周期需繼承這些文件以避免頻繁打開/關閉。

判斷舊cycle(old_cycleopen_files鏈表的第一個節點(part)是否有元素

open_filesngx_list_t類型,內部由多個ngx_list_part_t節點組成,每個節點包含多個元素。

Ubuntu 下 nginx-1.24.0 源碼分析 - ngx_list_t-CSDN博客

如果舊cycleopen_files存在元素,進入計算總元素數的邏輯

初始化容量?n?為舊周期文件數量

獲取舊周期?open_files?列表第一個分片(part)的元素數量。

ngx_list_t?是分片鏈表結構,每個分片(part)包含?nelts?個元素。
此處初始化?n?為第一個分片的元素數。

遍歷舊周期?open_files?的所有分片,累加總元素數到?n

ngx_list_t?可能包含多個分片(如元素數量超過單個分片容量),需遍歷所有分片統計總數。

若舊周期無文件,設置初始容量?n = 20


if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t))!= NGX_OK){ngx_destroy_pool(pool);return NULL;}

初始化新周期的?open_files?列表。

pool:內存池,用于管理列表內存。

n:初始容量(繼承舊文件數或默認 20)。

sizeof(ngx_open_file_t):每個元素的大小(文件描述符結構)。

Ubuntu 下 nginx-1.24.0 源碼分析 - ngx_list_init-CSDN博客


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

判斷舊周期(old_cycle)的共享內存列表是否非空。
shared_memory?存儲?nginx?的共享內存區域
在平滑重啟或重新配置時,新周期需繼承這些區域以避免重復創建。

獲取舊周期共享內存列表第一個分片(part)的元素數量

ngx_list_t?是分片鏈表結構,每個分片(part)包含?nelts?個元素。此處初始化?n?為第一個分片的元素數。

遍歷舊周期?shared_memory?的所有分片,累加總元素數到?n

ngx_list_t?可能包含多個分片(如元素數量超過單個分片容量),需遍歷所有分片統計總數。

若舊周期無共享內存,設置初始容量?n = 1


  if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t))!= NGX_OK){ngx_destroy_pool(pool);return NULL;}

初始化新周期的?shared_memory?列表。


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

根據舊周期(old_cycle)的監聽套接字數量設置新周期的初始容量 n
若舊周期無監聽套接字,則默認預分配 10 個元素。

old_cycle->listening.nelts 是舊周期監聽數組的元素數量。
若存在舊監聽套接字,繼承其數量;否則使用默認值 10
監聽數組(listening)存儲 Nginx 監聽的端口和套接字信息(如 listen 80;)。

在 Nginx 啟動時,所有監聽套接字會被初始化并集中存儲到 cycle->listening 數組中,方便后續統一操作(如綁定、監聽、關閉)。

初始化階段:在?ngx_init_cycle()?函數中,Nginx 會遍歷?cycle->listening?數組,為每個監聽創建套接字并設置為監聽狀態。

平滑重啟:當配置文件更改時,Nginx 可以平滑地切換到新配置,而不中斷當前連接。

這需要能夠比較新舊配置中的監聽端口,cycle->listening?提供了這種能力


  if (ngx_array_init(&cycle->listening, pool, n, sizeof(ngx_listening_t))!= NGX_OK){ngx_destroy_pool(pool);return NULL;}

初始化?cycle->listening?數組


    ngx_memzero(cycle->listening.elts, n * sizeof(ngx_listening_t));

將監聽數組的前?n?個元素清零。

ngx_memzero?是?memset?的封裝,確保內存初始化為 0

動態數組分配的內存可能包含臟數據,直接使用可能導致未定義行為(如誤判套接字狀態)


   ngx_queue_init(&cycle->reusable_connections_queue);

初始化可重用連接隊列:
cycle->reusable_connections_queue 初始化為一個空的雙向鏈表(隊列),用于管理可重用的空閑連接(ngx_connection_t)。

ngx_queue_t 是 Nginx 的雙向鏈表節點結構

ngx_queue_init(q) 宏會將隊列的 prev next 指針均指向自身,表示隊列為空。

隊列用途:
reusable_connections_queue 存儲當前未被使用的連接對象(如已關閉的 TCP 連接),這些連接可被重新分配以避免頻繁創建/銷毀的開銷。

頻繁調用 accept() 創建新連接會導致性能下降,而重用空閑連接可顯著降低延遲。

資源復用:
當連接關閉時,Nginx 不會立即釋放其資源(如套接字、內存),而是將其放入 reusable_connections_queue,等待后續請求復用。

在內存緊張時,可通過調整隊列大小(worker_connections)動態平衡資源。

Ubuntu 下 nginx-1.24.0 源碼分析 - ngx_queue_init-CSDN博客


    cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));if (cycle->conf_ctx == NULL) {ngx_destroy_pool(pool);return NULL;}

從內存池 pool 中分配一個指針數組 conf_ctx,每個元素對應一個模塊的配置結構指針。

ngx_max_module:編譯時確定的模塊總數

sizeof(void *):每個指針的大小

數組長度為 ngx_max_module,索引為模塊的唯一標識符(module->index)。

若內存分配失敗,銷毀內存池并終止初始化。

Ubuntu 下 nginx-1.24.0 源碼分析 - conf_ctx-CSDN博客


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

調用?gethostname()?系統調用獲取本地主機名,存儲到?hostname?緩沖區。

緩沖區大小為?NGX_MAXHOSTNAMELEN

若調用失敗(返回?-1),記錄致命錯誤(NGX_LOG_EMERG),銷毀內存池并終止初始化。

gethostname-CSDN博客


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

確保?hostname?以?\0?結尾,避免未終止字符串導致的安全風險。

Linux 的?gethostname()?在緩沖區不足時靜默截斷,但不會添加?\0
手動設置最后一個字節為?\0,確保字符串合法性。

計算主機名的實際長度(不含終止符),存儲到?cycle->hostname.len


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

從內存池?pool?分配內存,存儲主機名的副本

ngx_pnalloc?分配指定長度的內存
若分配失敗,銷毀內存池并終止初始化。


    ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len);

將主機名轉換為全小寫,存儲到 cycle->hostname.data

ngx_strlow 是 Nginx 的封裝函數,逐字符轉換為小寫。

主機名在 DNS 和 HTTP 協議中通常不區分大小寫,統一格式避免配置或路由問題。

統一小寫格式,簡化后續比較和匹配邏輯(如虛擬主機配置)。


    if (ngx_cycle_modules(cycle) != NGX_OK) {ngx_destroy_pool(pool);return NULL;}

調用 ngx_cycle_modules 初始化 cycle->modules 數組,該數組包含所有核心模塊的指針。

Nginx 模塊分為核心模塊(NGX_CORE_MODULE)、事件模塊、HTTP 模塊等。

ngx_cycle_modules 會遍歷全局模塊列表(ngx_modules),篩選出核心模塊并按優先級排序。
若模塊初始化失敗(如內存不足),立即回滾資源。

Ubuntu 下 nginx-1.24.0 源碼分析 - ngx_cycle_modules-CSDN博客


    for (i = 0; cycle->modules[i]; i++) {if (cycle->modules[i]->type != NGX_CORE_MODULE) {continue;}

遍歷所有核心模塊

Ubuntu 下 nginx-1.24.0 源碼分析 - cycle->modules[i]->type-CSDN博客


module = cycle->modules[i]->ctx;

獲取核心模塊的配置

module 的類型是:

ngx_core_module_t   *module;

Ubuntu 下 nginx-1.24.0 源碼分析 - cycle->modules[i]->ctx-CSDN博客

Ubuntu 下 nginx-1.24.0 源碼分析 - ngx_core_module_t-CSDN博客


?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/72935.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/72935.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/72935.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

qt 操作多個sqlite文件

qt 操作多個sqlite文件 Chapter1 qt 操作多個sqlite文件1. 引入必要的頭文件2. 創建并連接多個SQLite數據庫3. 代碼說明4. 注意事項 Chapter2 qt 多線程操作sqlite多文件1. 引入必要的頭文件2. 創建數據庫操作的工作線程類3. 在主線程中創建并啟動多個工作線程4. 代碼說明5. 運…

最新版本WebContext構造函數-避坑

import org.thymeleaf.context.IWebContext; import org.thymeleaf.context.WebContext; 當你想把頁面信息全部獲取出來存到redis緩存中使用時&#xff0c;SpringWebContext在Spring5中報錯 SpringWebContext ctx new SpringWebContext(request, response,request.getServlet…

用Python分割并高效處理PDF大文件

在處理大型PDF文件時&#xff0c;將它們分解成更小、更易于管理的塊通常是有益的。這個過程稱為分區&#xff0c;它可以提高處理效率&#xff0c;并使分析或操作文檔變得更容易。在本文中&#xff0c;我們將討論如何使用Python和為Unstructured.io庫將PDF文件劃分為更小的部分。…

neo4j隨筆-將csv文件導入知識圖譜

目錄 導入前的準備 導入csv文件 導入nodes1.1.csv并動態為節點添加標簽 ?編輯導入relations1.1.csv并動態為關系添加標簽 結果 導入前的準備 我有兩個csv文件 nodes1.1.csv存放節點信息,用記事本打開&#xff0c;能正常顯示&#xff0c;且編碼為UTF-8&#xff0c;就可以…

cpu 多級緩存L1、L2、L3 與主存關系

現代 CPU 的多級緩存&#xff08;L1、L2、L3&#xff09;和主存&#xff08;DRAM&#xff09;構成了一個層次化的內存系統&#xff0c;旨在通過減少內存訪問延遲和提高數據訪問速度來優化計算性能。以下是對多級緩存和主存的詳細解析&#xff1a; 1. 緩存層次結構 現代 CPU 通…

C++:入門詳解(關于C與C++基本差別)

目錄 一.C的第一個程序 二.命名空間&#xff08;namespace&#xff09; 1.命名空間的定義與使用&#xff1a; &#xff08;1&#xff09;命名空間里可以定義變量&#xff0c;函數&#xff0c;結構體等多種類型 &#xff08;2&#xff09;命名空間調用&#xff08;&#xf…

Python的學習篇(七)--網頁結構

七、網頁&#xff08;HTML&#xff09;結構 7.1 HTML介紹 HTML(Hyper Text Markup Language)&#xff0c;超文本標記語言。 超文本&#xff1a;比文本的功能要強大&#xff0c;通過鏈接和交互式的方式來組織與呈現信息的文本形式。不僅僅有文本&#xff0c;還可以包含圖片、…

*VulnHub-FristiLeaks:1.3暴力解法、細節解法,主打軟硬都吃,隧道搭建、尋找exp、提權、只要你想沒有做不到的姿勢

*VulnHub-FristiLeaks:1.3暴力解法、細節解法&#xff0c;主打軟硬都吃&#xff0c;隧道搭建、尋找exp、提權、只要你想沒有做不到的姿勢 一、信息收集 1、掃靶機ip 經典第一步&#xff0c;掃一下靶機ip arp-scan -l 掃描同網段 nmap -sP 192.168.122.0/242、指紋掃描、端口…

PHP:格式化JSON為PHP語法格式

1. 原生函數 $arr [1,2,3,4]; $str var_export($a,true); var_dump($str); 2. 自定義方法 class Export{private static $space;private static function do($a, string $prev){$res ;$next $prev . self::$space;if (is_array($a)) {$res . [;foreach ($a as $k > $…

【Python 數據結構 9.樹】

我裝作漠視一切&#xff0c;其實我在乎的太多&#xff0c;但我知道抓得越緊越容易失去 —— 25.3.6 一、樹的基本概念 1.樹的定義 樹是n個結點的有限集合&#xff0c;n0時為空樹。當n大于0的時候&#xff0c;滿足如下兩個條件&#xff1a; ① 有且僅有一個特定的結點&#xff…

pyqt聯合designer的運用和設置

PyQt Designer 簡介 PyQt Designer 是一個用于創建和設計 PyQt 應用程序用戶界面的可視化工具。它允許用戶通過拖放方式添加和排列各種控件,如按鈕、文本框、滑塊等,并設置它們的屬性和樣式,從而快速構建出美觀且功能完整的 UI 界面。 Windows版本:【免費】安裝包別管啊啊…

純html文件實現目錄和文檔關聯

目錄結構 效果圖 代碼 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>項目結題報告</title><style lang"scss">::-webkit-scrollbar {width: 6px;height: 6px;}::-webkit-scro…

python用戶圖形界面wxpython庫安裝與使用

要開始使用 wxPython 庫來創建 Python 用戶圖形界面&#xff0c;首先需要安裝這個庫。在大多數情況下&#xff0c;你可以通過 pip 來安裝 wxPython。下面我會指導你完成安裝過程&#xff0c;并給出一個簡單的例子來展示如何使用 wxPython 創建一個基本的窗口應用程序。 安裝 w…

MongoDB winx64 msi包安裝詳細教程

首先我們可以從官網上選擇對應版本和對應的包類型進行安裝&#xff1a; 下載地址&#xff1a;Download MongoDB Community Server | MongoDB 這里可以根據自己的需求&#xff0c; 這里我選擇的是8.0.5 msi的版本&#xff0c;采用的傳統裝軟件的方式安裝。無需配置命令。 下載…

如何借助 ArcGIS Pro 高效統計基站 10km 范圍內的村莊數量?

在當今數字化時代&#xff0c;地理信息系統&#xff08;GIS&#xff09;技術在各個領域都發揮著重要作用。 特別是在通信行業&#xff0c;對于基站周邊覆蓋范圍內的地理信息分析&#xff0c;能夠幫助我們更好地進行網絡規劃、資源分配以及市場分析等工作。 今天&#xff0c;就…

saltstack通過master下發腳本批量修改minion_id,修改為IP

通過master下發腳本批量修改minion_id&#xff0c;以修改為IP為例 通過cmd.script遠程執行shell腳本修改minion_id&#xff0c;步驟如下: # 下發腳本并執行 >> salt old_minion_id cmd.script salt://modify_minion_id.sh saltenvdev #輸出結果 old_minion_id:Minion di…

【大模型】WPS 接入 DeepSeek-R1詳解,打造全能AI辦公助手

目錄 一、前言 二、WPS接入AI工具優勢??????? 三、WPS接入AI工具兩種方式 3.1 手動配置的方式 3.2 Office AI助手 四、WPS手動配置方式接入AI大模型 4.1 安裝VBA插件 4.1.1 下載VBA插件并安裝 4.2 配置WPS 4.3 WPS集成VB 4.4 AI助手效果測試 4.5 配置模板文…

《蒼穹外賣》SpringBoot后端開發項目重點知識整理(DAY1 to DAY3)

目錄 一、在本地部署并啟動Nginx服務1. 解壓Nginx壓縮包2. 啟動Nginx服務3. 驗證Nginx是否啟動成功&#xff1a; 二、導入接口文檔1. 黑馬程序員提供的YApi平臺2. YApi Pro平臺3. 推薦工具&#xff1a;Apifox 三、Swagger1. 常用注解1.1 Api與ApiModel1.2 ApiModelProperty與Ap…

Mysql5.7-yum安裝和更改mysql數據存放路徑-2020年記錄

記錄下官網里用yum rpm源安裝mysql, 1 官網下載rpm https://dev.mysql.com/downloads/repo/yum/ https://dev.mysql.com/doc/refman/5.7/en/linux-installation-yum-repo.html&#xff08;附官網操作手冊&#xff09; wget https://repo.mysql.com//mysql80-community-release…

HTML5(Web前端開發筆記第一期)

p.s.這是萌新自己自學總結的筆記&#xff0c;如果想學習得更透徹的話還是請去看大佬的講解 目錄 三件套標簽標題標簽段落標簽文本格式化標簽圖像標簽超鏈接標簽錨點鏈接默認鏈接地址 音頻標簽視頻標簽 HTML基本骨架綜合案例->個人簡介列表表格表單input標簽單選框radio上傳…