xtc_mctx(3)
---xtc_mctx(3)
hierarchical memory contexts with cleanup callbacks
| XTC_MCTX(3) | Library Functions Manual | XTC_MCTX(3) |
NAME
xtc_mctx_create,
xtc_mctx_destroy,
xtc_mctx_alloc,
xtc_mctx_calloc,
xtc_mctx_strdup,
xtc_mctx_free,
xtc_mctx_register_cleanup,
xtc_mctx_name,
xtc_mctx_total_bytes,
xtc_mctx_total_chunks,
xtc_mctx_reset,
xtc_arena_group_create,
xtc_arena_group_destroy,
xtc_arena_group_mctx,
xtc_arena_group_add,
xtc_arena_group_discard,
xtc_arena_group_size —
hierarchical memory contexts with cleanup
callbacks
SYNOPSIS
#include <xtc.h>
#include <xtc_mctx.h>
int
xtc_mctx_create(xtc_mctx_t
*parent, const char
*name, unsigned
flags, xtc_mctx_t
**out);
void
xtc_mctx_destroy(xtc_mctx_t
*ctx);
void *
xtc_mctx_alloc(xtc_mctx_t
*ctx, size_t
size);
void *
xtc_mctx_calloc(xtc_mctx_t
*m, size_t n,
size_t size);
void *
xtc_mctx_strdup(xtc_mctx_t
*m, const char
*s);
void
xtc_mctx_free(xtc_mctx_t
*m, void *p);
int
xtc_mctx_register_cleanup(xtc_mctx_t
*m, xtc_mctx_cleanup_fn
fn, void
*user);
const char *
xtc_mctx_name(const
xtc_mctx_t *m);
size_t
xtc_mctx_total_bytes(const
xtc_mctx_t *m);
size_t
xtc_mctx_total_chunks(const
xtc_mctx_t *m);
void
xtc_mctx_reset(xtc_mctx_t
*ctx);
int
xtc_arena_group_create(const
char *name,
xtc_arena_group_t
**out);
void
xtc_arena_group_destroy(xtc_arena_group_t
*g);
xtc_mctx_t *
xtc_arena_group_mctx(xtc_arena_group_t
*g);
int
xtc_arena_group_add(xtc_arena_group_t
*g);
int
xtc_arena_group_discard(xtc_arena_group_t
*g, int reason,
int64_t timeout_ns,
int *out_all_gone);
int
xtc_arena_group_size(xtc_arena_group_t
*g);
DESCRIPTION
xtc_mctx is a hierarchical memory context,
modeled on PostgreSQL's MemoryContext. Allocations
belong to a context; destroying the context bulk-frees everything in it
(plus all child contexts recursively). Useful for request-scoped memory:
create a context per request, allocate freely, destroy at the end without
tracking individual frees.
xtc_mctx_create()
takes a flags bitmask of
XTC_MCTX_* values:
XTC_MCTX_DEFAULT (0) for an unlocked context, or
XTC_MCTX_THREAD_SAFE for one that is internally
locked. A NULL parent produces
a root context; name is copied for diagnostics.
Each context can register cleanup callbacks fired on destroy (before the bulk-free) to release non-memory resources.
No context lock is held while a cleanup
callback runs, so a callback may call back into its own context
(xtc_mctx_total_bytes(),
xtc_mctx_total_chunks(),
or an allocation). What it must NOT do is reset or destroy the very context
running it. Callbacks are detached before they run, so each fires exactly
once even if the context is reset concurrently; register again if the next
reset should call it too.
xtc_mctx_alloc()
returns raw memory within the context;
xtc_mctx_calloc()
zeroes an n by size array; and
xtc_mctx_strdup()
copies string s into the context. All live until the
context is reset or destroyed.
xtc_mctx_free()
optionally releases a single allocation early.
xtc_mctx_register_cleanup()
adds a callback fn run in LIFO order at
reset/destroy.
xtc_mctx_name()
returns the context's name; xtc_mctx_total_bytes()
and xtc_mctx_total_chunks() report the memory and
chunk count currently charged to the context.
Arena groups: wholesale shared-state discard on kill
An arena group binds a set of member fibers to one discardable
arena, giving a recovery boundary smaller than the whole process -- the
analogue of a crash-only database reinitialising shared memory.
xtc_arena_group_create()
makes an empty group with a fresh thread-safe arena, and
xtc_arena_group_destroy()
frees it (it does not kill members).
xtc_arena_group_mctx()
returns the arena; members allocate their SHARED state there, and
xtc_arena_group_add()
registers the calling fiber as a member. The group records each member's pid
together with its owner loop (the loop it was spawned on), because a pid
alone is executor-relative and can name an unrelated process on another
standalone loop. A member's owner loop must not be finalized while the group
still lists that member: keep it alive until a
xtc_arena_group_discard()
reports all_gone == 1, or until
xtc_arena_group_destroy().
xtc_arena_group_discard() is the point of the
facility: it
xtc_exit_pid_deadline()s
every live member, waits until ALL are confirmed gone, and only THEN resets
the arena -- so the shared state a killed fiber was mid-mutating is thrown
away with nothing alive still touching it. If a member is wedged inside a
mask (kill deferred) and still alive at its deadline, the arena is left
INTACT and the caller is told all_gone == 0, so it
escalates to the whole-process fail-stop rather than discard state a live
fiber may still touch.
xtc_arena_group_size()
reports the current member count.
EXAMPLES
xtc_mctx_t *root, *req; xtc_mctx_create(NULL, "root", XTC_MCTX_DEFAULT, &root); xtc_mctx_create(root, "request-42", XTC_MCTX_DEFAULT, &req); /* Allocate request-scoped objects. */ char *buf = xtc_mctx_alloc(req, 4096); struct widget *w = xtc_mctx_alloc(req, sizeof *w); /* Done; bulk-free everything in req. */ xtc_mctx_destroy(req);
SEE ALSO
HISTORY
Appeared in xtc 0.1.
| September 21, 2026 | Debian |