nginx/nginx
Cycle (ngx_cycle_t)
Active contributors: Maxim Dounin, Sergey Kandaurov
What it is
The ngx_cycle_t is nginx's "world." It owns the parsed configuration, the listening sockets, the connection table, the module list, the open file table, and the shared-memory zones. Almost every long-lived state pointer in the codebase ultimately roots back to a cycle.
There is one global ngx_cycle (a volatile ngx_cycle_t *) that everyone reads. On a SIGHUP reload, a new cycle is built, the global pointer is swapped, and the old cycle keeps running until its workers drain — that's the basis of the zero-downtime reload model.
Definition
src/core/ngx_cycle.h:
struct ngx_cycle_s {
void ****conf_ctx; /* per-module config trees */
ngx_pool_t *pool; /* allocations live here */
ngx_log_t *log; /* the cycle's logger */
ngx_log_t new_log; /* in-progress log during reload */
ngx_uint_t log_use_stderr;
ngx_connection_t **files; /* fd -> connection */
ngx_connection_t *free_connections; /* per-worker free list */
ngx_uint_t free_connection_n;
ngx_module_t **modules;
ngx_uint_t modules_n;
ngx_uint_t modules_used;
ngx_queue_t reusable_connections_queue;
ngx_uint_t reusable_connections_n;
time_t connections_reuse_time;
ngx_array_t listening; /* ngx_listening_t[] */
ngx_array_t paths; /* ngx_path_t *[] */
ngx_array_t config_dump;
ngx_rbtree_t config_dump_rbtree;
ngx_rbtree_node_t config_dump_sentinel;
ngx_list_t open_files; /* ngx_open_file_t */
ngx_list_t shared_memory; /* ngx_shm_zone_t */
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 error_log;
ngx_str_t lock_file;
ngx_str_t hostname;
};Lifecycle
Created by ngx_init_cycle(old_cycle) (src/core/ngx_cycle.c):
- Allocate a new
ngx_pool_t— everything below comes out of it. - Allocate the cycle struct from that pool.
- Copy paths, prefix, conf_file from
old_cycle(or the CLI args on first init). - For each module, call
create_conf(CORE modules) to build empty config structs. - Parse
nginx.confinto the new cycle (viangx_conf_parse). - For each module, call
init_conf(defaults + validation). - Open the shared zones; reattach to old shm where the size and tag match.
- Open the listening sockets — reusing fds from
old_cycle->listeningwhere possible. - Allocate connection table (
connections,read_events,write_events). - For each module, call
init_module(cycle). - Open log files.
- Return the new cycle.
If anything fails, the function returns NULL and the old cycle continues to run. This is the invariant nginx leans on: the old cycle is preserved, the old workers are still serving, and the operator can just edit the config and try again.
Old cycle handoff
After ngx_init_cycle returns successfully, the master:
- Sets the new global
ngx_cycle = new_cycle. - Forks new workers against the new cycle.
- Sends
NGX_CMD_QUITto old workers; they finish in-flight requests and exit. - Eventually destroys the old cycle (
ngx_destroy_cycle()— clearsold_cycle->pool).
Listening sockets stay open across this transition: the new workers inherit them via cycle->listening carrying over the same fds.
Working with cycles
Most code never creates or destroys a cycle. It just reads ngx_cycle->conf_ctx, allocates from ngx_cycle->pool, or registers callbacks via the cycle's facilities (open file, shared memory).
Common idioms:
ngx_cycle_t *cycle = ngx_cycle; /* read the global */
void *core_conf = ngx_get_conf(cycle->conf_ctx, ngx_core_module);
ngx_pool_t *pool = cycle->pool; /* short-lived allocations only at startup */
ngx_log_t *log = cycle->log;In HTTP modules, the per-module config is pulled out via ngx_http_cycle_get_module_main_conf.
Pitfalls
- Don't store pointers across cycle boundaries. A pointer into the old cycle's pool becomes a use-after-free after
ngx_destroy_cycle. Modules that need long-lived state across reloads use shared memory zones, not the cycle pool. init_modulecan be called multiple times — once on initial startup, once on each successful reload. Make it idempotent and cheap.cycle->listeningis array ofngx_listening_t, not pointers. Index, don't pointer-traverse.
Cross-references
- systems/process-model — how master/worker reload juggles cycles
- systems/configuration — how
ngx_init_cyclewalks modules and parses config - primitives/module — modules' role inside the cycle
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.