Repository navigation
Memory Management
Headers: <cwist/core/mem/alloc.h>, <cwist/core/mem/arena.h>,
<cwist/core/mem/gc.h>, <cwist/core/mem/intercept.h>
CWIST's default model is explicit: memory you allocate with cwist_alloc()
you free with cwist_free(), objects you _create you _destroy. On top of
that it offers scoped cleanup, request arenas, and an opt-in epoch-based
garbage collector.
| Function | Description |
|---|---|
void *cwist_alloc(size_t size) |
Zeroed memory tracked by libttak. |
void *cwist_alloc_array(size_t count, size_t elem_size) |
Zeroed array (overflow-checked). |
void *cwist_realloc(void *ptr, size_t new_size) |
Resize. |
char *cwist_strdup(const char *s) / cwist_strndup(s, n)
|
Copy strings. |
void cwist_free(void *ptr) |
Free memory from any of the above (NULL is fine). |
void *cwist_malloc(size_t size) |
Zeroed memory through the shared owner context (cwist_create_owner()). |
Buffers that CWIST functions hand you (serialized responses, URL strings,
cookie encodings, JWTs, ...) come from this allocator unless a page says
otherwise; release them with cwist_free(). A few APIs use plain malloc
instead (db_crypt, db_sync, the metrics renderer, JSON-heal callbacks);
their pages say so.
cJSON's allocator is redirected to cwist_alloc at process start, so cJSON
memory is released with cJSON_free() / cJSON_Delete() as usual.
On GCC and Clang, attach CWIST_DEFER_FREE to a pointer declaration and the
pointer is freed when the enclosing block exits, on every path:
char *token CWIST_DEFER_FREE = cwist_jwt_sign(payload, secret, 3600);
if (!token) return; /* freed (NULL) here */
send_token(token); /* and freed at the end of the block */cwist_alloc_scoped(var, type, size) declares and allocates in one line:
cwist_alloc_scoped(name, char *, 64);
snprintf(name, 64, "user-%d", id);cwist_scratch_t with CWIST_SCRATCH_DEFER and cwist_scratch_alloc() gives
block-scoped scratch memory that prefers a recycled arena generation over the
allocator:
cwist_scratch_t s CWIST_SCRATCH_DEFER = {0};
unsigned char *buf = cwist_scratch_alloc(&s, needed); /* not zeroed */Only use these for pointers that do not leave the block (not stored in a struct, a global or a queued job). On compilers without the cleanup attribute (TinyCC) they do nothing and you must free explicitly.
<cwist/core/mem/arena.h> provides bump allocation from a libttak arena
generation, released in one step. CWIST allocates each request's and
response's fixed structures this way (a full HTTP/1.1 exchange uses about
3.5 KB of the 8 KiB default generation; spills go to the heap).
| Function | Description |
|---|---|
cwist_arena_t *cwist_arena_create(size_t generation_bytes) |
Arena (0 = 8 KiB default, recycled per thread). NULL on failure. |
void *cwist_arena_alloc(cwist_arena_t *a, size_t size) |
Aligned, not zeroed; NULL when the generation is full. |
bool cwist_arena_owns(const cwist_arena_t *a, const void *p) |
Whether p came from the arena. |
void cwist_arena_destroy(cwist_arena_t *a) |
Release everything at once. |
cwist_full_gc(true) turns on epoch-based reclamation for the whole process:
cwist_alloc blocks a thread forgets to free are reclaimed, and connections a
thread or the process still owns at exit are closed. Pointers that must
outlive their scope are handed off with cwist_gc_scope_disown(). Opting a
translation unit into CWIST_INTERCEPT_MALLOC routes its plain
malloc/free through the same pipeline. Read Full GC for the
design and measured costs, and Async GC Ownership for
handing memory between threads.
CWIST links libttak for its allocator and
concurrency primitives: generational arenas (static files and cache blobs are
retired one generation at a time), epoch-based reclamation (readers never
block while buffers are swapped), detachable memory for zero-copy bodies, and
a lock-free job queue. CWIST_MALLOC_ARENA_MAX=1 caps glibc's malloc arenas
per worker; see Configuration and Environment.
CWIST wiki, written against the dev branch of c4punks/CWIST. Pages marked "Source:" are generated from files under docs/; fix those in the repository. Questions: Discord.
Getting started
- Installation
- Quick Start
- Linking
- Server Modes
- Configuration and Environment
- Project CLI
- Tutorial / Korean
- Examples and Tutorials
Guides
Core
- API Reference
- Application
- Routing
- Middleware
- Requests and Responses
- Async Handlers
- Streaming Responses
- Error Handling
- Graceful Shutdown
- Multiport
Protocols
- HTTPS and TLS
- HTTP/2
- HTTP/3 and QUIC
- WebTransport
- WebSocket
- Server-Sent Events
- gRPC Server
- gRPC Client
- Protobuf and Codegen
- GraphQL
- WebRTC DataChannels
- HTTP Clients
Web features
- Static Files and Assets
- Big Dumb Reply Cache
- Compression
- Cookies
- Sessions and Flash
- Query Maps
- Multipart Uploads
- HTML Components
- Templates
- JSON
- Validation
- OpenAPI
Security
Data
Runtime
- Memory Management
- Full GC
- Async GC Ownership
- SString
- Reactor and I/O
- Metrics and Health
- Logging
- Testing
Platforms
Performance notes
- Benchmark Methodology
- C1M File Limits
- Reactor Fairness
- Cooperative Queuing
- Classic Pool Starvation
- Reactor Wakeup
- wrk Dual Histogram
- FIXED Endpoint Cache
- ADR-0001
- Durable Queue Gate
- Mux References
Project