nginx/nginx
Core utilities
Active contributors: Sergey Kandaurov, Maxim Dounin, Roman Arutyunyan
Purpose
src/core/ is the foundation that every other subsystem rests on: memory management (pools, slabs, shared zones), the standard data structures (arrays, lists, queues, hashes, red-black trees, radix trees), the string type, logging, time tracking, and a few specialized utilities (regex wrapper, MD5/SHA1, CRC32, syslog, proxy-protocol parsing). Almost nothing here depends on anything outside src/core/ — so this is the right starting point for reading the codebase.
Directory layout
src/core/
├── nginx.c # main(), CLI parsing, core_module
├── nginx.h # NGINX_VERSION
├── ngx_core.h # the umbrella include
├── ngx_config.h # platform / compiler abstraction
├── ngx_palloc.{c,h} # pool allocator
├── ngx_slab.{c,h} # slab allocator (over shared memory)
├── ngx_shmtx.{c,h} # mutex over shared memory
├── ngx_rwlock.{c,h} # spinlock-based rwlock
├── ngx_buf.{c,h} # buffers + chains
├── ngx_array.{c,h} # ngx_array_t
├── ngx_list.{c,h} # ngx_list_t
├── ngx_queue.{c,h} # intrusive doubly-linked list
├── ngx_hash.{c,h} # build-once hash, wildcard hash
├── ngx_rbtree.{c,h} # red-black tree
├── ngx_radix_tree.{c,h} # bitwise radix tree (for IP prefixes)
├── ngx_string.{c,h} # ngx_str_t and friends
├── ngx_inet.{c,h} # CIDR parsing, address printing
├── ngx_log.{c,h} # error log, debug log
├── ngx_syslog.{c,h} # syslog target
├── ngx_times.{c,h} # cached time (ngx_current_msec)
├── ngx_parse.{c,h} # number/size parsing helpers
├── ngx_parse_time.{c,h} # time / date string parsing
├── ngx_regex.{c,h} # PCRE / PCRE2 wrapper
├── ngx_md5.{c,h} # MD5 (used unless OpenSSL provides it)
├── ngx_sha1.{c,h} # SHA-1 fallback
├── ngx_crypt.{c,h} # password hash for auth_basic
├── ngx_crc.h, ngx_crc32.{c,h}, ngx_murmurhash.{c,h}
├── ngx_file.{c,h} # path / file abstractions
├── ngx_open_file_cache.{c,h} # cached open() of static files
├── ngx_output_chain.c # chain-based output (sendfile_max_chunk, etc.)
├── ngx_resolver.{c,h} # async DNS
├── ngx_proxy_protocol.{c,h} # PROXY protocol v1/v2
├── ngx_thread_pool.{c,h} # the worker thread pool (--with-threads)
├── ngx_conf_file.{c,h} # the configuration parser
├── ngx_module.{c,h} # module registration / lookup
├── ngx_cycle.{c,h} # the cycle struct + ngx_init_cycle()
├── ngx_connection.{c,h} # the connection table
├── ngx_bpf.{c,h} # eBPF loader (Linux QUIC reuseport)
└── ngx_cpuinfo.c # CPUID detectionKey abstractions
| Type / function | File | Role |
|---|---|---|
ngx_pool_t / ngx_palloc |
src/core/ngx_palloc.h |
Bump allocator with cleanup callbacks. The default everywhere. |
ngx_slab_pool_t / ngx_slab_alloc |
src/core/ngx_slab.h |
Class-based allocator over shared memory. Used by limit_*, ssl cache. |
ngx_shm_zone_t |
src/core/ngx_cycle.h |
A named shared memory zone. Created by ngx_shared_memory_add(). |
ngx_buf_t, ngx_chain_t |
src/core/ngx_buf.h |
Span of bytes (memory-backed or file-backed) and a linked-list link. |
ngx_array_t |
src/core/ngx_array.h |
Growable typed array. |
ngx_list_t |
src/core/ngx_list.h |
Array of arrays (so adding doesn't invalidate previous pointers). |
ngx_queue_t |
src/core/ngx_queue.h |
Intrusive doubly-linked list head + node. |
ngx_hash_t, ngx_hash_combined_t |
src/core/ngx_hash.h |
Read-only hash built once; combined variant supports *.example.com. |
ngx_rbtree_t |
src/core/ngx_rbtree.h |
Red-black tree. Used by timer wheel, file cache, OCSP cache, SSL sessions. |
ngx_radix_tree_t |
src/core/ngx_radix_tree.h |
Radix tree on IPv4 / IPv6 prefixes. Backs geo, realip. |
ngx_str_t |
src/core/ngx_string.h |
{ size_t len; u_char *data; } — the string type. |
ngx_log_error(), ngx_log_debug*() |
src/core/ngx_log.c |
The logging entry points. |
ngx_time_update(), ngx_current_msec |
src/core/ngx_times.c |
Cached wall-clock time, refreshed once per event loop iteration. |
ngx_resolve_name() |
src/core/ngx_resolver.c |
Async DNS resolution. |
ngx_thread_pool_t |
src/core/ngx_thread_pool.h |
A pool of worker threads for blocking operations like aio threads. |
How memory works
graph TD
Cycle[Cycle pool<br/>cycle->pool] -->|owns| ConfigState[Parsed config / hashes]
Cycle -->|owns| ListenSockets[Listening sockets]
Conn[Connection pool<br/>c->pool] -->|owns| ConnBufs[Read/write buffers]
Conn -->|owns| TLS[SSL connection state]
Req[Request pool<br/>r->pool] -->|owns| Headers[Parsed headers]
Req -->|owns| Vars[Variable values]
Req -->|owns| FilterCtxs[Filter contexts]
Sub[Subrequest pool] -->|inherits| Req
Shared[Shared zone<br/>slab pool] -->|owns| LimitState[limit_req zones]
Shared -->|owns| SSLCache[SSL session cache]
Shared -->|owns| UpstreamZone[Upstream peers]There are four lifetimes:
- Cycle — created once at startup and once per reload. Anything in
cycle->poollives for the duration of the cycle. - Connection — created on accept, destroyed on close. Connection-private data goes here.
- Request — created at request start, destroyed at
ngx_http_finalize_request. Subrequests get their own pools but share the connection. - Shared zone —
mmap-backed, lifetime = process group. The slab allocator carves these up.
Functions that need to hold a buffer past the current pool's lifetime register a cleanup:
ngx_pool_cleanup_t *cln = ngx_pool_cleanup_add(pool, sizeof(my_cleanup_t));
cln->handler = my_cleanup_handler;
cln->data = my_data;The handler runs in LIFO order when the pool is destroyed.
Time
ngx_current_msec and ngx_cached_time are cached values. They're refreshed at the top of each event-loop iteration by ngx_time_update() (src/core/ngx_times.c). Inside an event handler the clock is stable — fast, but you can't expect sub-millisecond resolution. Anything that needs accurate wall time should call gettimeofday() directly.
The timer wheel (src/event/ngx_event_timer.c) is implemented as a red-black tree keyed by deadline. ngx_add_timer(ev, msec) inserts; ngx_event_expire_timers() runs at the top of each loop iteration to fire expired ones.
Strings, the careful version
ngx_str_t carries a length, not a NUL terminator. The reason is that nginx receives input as recv() chunks, doesn't want to copy them, and doesn't want to add NULs in place. Functions consuming ngx_str_t must respect the length.
| Helper | Effect |
|---|---|
ngx_string("hello") |
Compile-time literal: { 5, (u_char *) "hello" } |
ngx_str_set(&s, "hello") |
Set both fields from a literal |
ngx_str_null(&s) |
{ 0, NULL } |
ngx_strlow(dst, src, n) |
Lowercase copy |
ngx_strncasecmp(a, b, n) |
Case-insensitive compare |
ngx_atoi, ngx_atosz, ngx_atofp |
Parsers for ints, sizes, fixed-point |
ngx_sprintf(dst, fmt, ...) |
Custom formatter; %V consumes ngx_str_t *, %xz is hex size_t |
Resolver
src/core/ngx_resolver.c is a hand-rolled async DNS client. Used by proxy_pass with a hostname, by resolver directive, by auth_request upstream, and by the mail proxy. Caches A, AAAA, SRV, and PTR records in the per-cycle resolver state.
Proxy protocol
src/core/ngx_proxy_protocol.c reads the v1 (text) and v2 (binary) PROXY protocol headers that upstream load balancers prepend to a TCP connection. Used by proxy_protocol listener directive. Sets the originating client address on the connection so logging and realip see the right value.
Integration points
- The HTTP, Mail, and Stream subsystems all build on these primitives. They allocate from pools, read from chains, log via
ngx_log_error, and store config via the hash and array helpers. - The event loop uses
ngx_rbtree_tfor the timer wheel andngx_queue_tfor posted-event lists. - The OS abstraction layer provides the OS-specific atomics (
src/os/unix/ngx_atomic.h), the file types, and the socket primitives thatsrc/core/relies on for cross-platform behavior.
Entry points for modification
Most changes here are surgical — adding a helper function, fixing an edge case in a parser, or swapping in a faster backend (like the SSE-accelerated string operations). Read the existing function in the file you want to touch, mirror the style, and run the full test suite. Any bug in src/core/ is felt by every other module, so coverage matters.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.