xtc_slab(3)

---

xtc_slab(3)

slab + magazine allocator

XTC_SLAB(3) Library Functions Manual XTC_SLAB(3)

xtc_slab_create, xtc_slab_destroy, xtc_slab_alloc, xtc_slab_free, xtc_slab_reap, xtc_slab_stat, xtc_slab_offset, xtc_slab_resolve, xtc_slab_pressure_listen, xtc_slab_pressure_listen_ex, xtc_slab_pressure_stop, xtc_slab_reaper_spawnslab + magazine allocator

#include <xtc.h>
#include <xtc_slab.h>

int
xtc_slab_create(const xtc_slab_opts_t *opts, xtc_slab_t **out);

void
xtc_slab_destroy(xtc_slab_t *slab);

void *
xtc_slab_alloc(xtc_slab_t *slab);

void
xtc_slab_free(xtc_slab_t *slab, void *obj);

int
xtc_slab_reap(xtc_slab_t *slab);

int
xtc_slab_stat(const xtc_slab_t *slab, xtc_slab_stats_t *out);

xtc_slab_off_t
xtc_slab_offset(const xtc_slab_t *slab, const void *p);

void *
xtc_slab_resolve(const xtc_slab_t *slab, xtc_slab_off_t off);

int
xtc_slab_pressure_listen(const char *psi_path, xtc_slab_pressure_fn fn, void *user);

int
xtc_slab_pressure_listen_ex(const char *psi_path, xtc_slab_pressure_fn fn, void *user, xtc_slab_pressure_t **out);

int
xtc_slab_pressure_stop(xtc_slab_pressure_t *handle);

int
xtc_slab_reaper_spawn(xtc_loop_t *loop, int64_t interval_ns, xtc_pid_t *out_pid);

xtc_slab is a libumem-style slab allocator with per-loop magazines. Every fixed-size hot-path allocation in xtc routes through it (lockmgr lock entries, proc link/monitor entries, RCU retired) (nodes, timer nodes); applications can use it directly for any pool of same-sized objects.

A slab is a cache of objects of a single size. Objects are carved from chunks (mmap'd regions, default 64 KiB); each chunk holds many slots. Free objects are linked through their first sizeof(void *) bytes.

: each thread keeps a small per-cache cache (default 16 slots) of recently-freed objects. Allocs hit the magazine (lock-free, no atomics); on miss the cache lock is taken and the magazine is refilled from a partial chunk. Frees push to the magazine; when full, the magazine spills back to the cache under lock.

: optional callbacks run once per object lifetime. Constructor on the first time an object is pulled from a slot; destructor at cache destroy or chunk reap.

Default. Chunks via mmap(2) MAP_ANONYMOUS.
Caller passes an mmap'd MAP_SHARED fd; the slab carves chunks from that region. Object handles are xtc_slab_off_t offsets that two processes can resolve to local pointers using (). The shared header at the start of the region holds an atomic cursor so concurrent processes don't collide on chunk allocation.

:

8-byte magic before+after every object; checked on free.
64-event ring of recent (alloc, free) events.
Backtrace each event (Linux/glibc only).
Always go through the cache lock. For diagnostic use.

control behaviour when no chunk can be allocated:

Return NULL. Default.
Brief usleep + retry once, then NULL.
() (debug builds).

() allocates a cache. opts is required and must set opts->name and opts->obj_size.

() returns a fresh object pointer or NULL on OOM. () returns it to the cache.

() drops magazines and returns empty chunks to the OS. Useful under memory pressure.

() attaches a callback that fires when Linux PSI memory pressure is detected. When triggered, all registered slab caches are reaped. Returns XTC_E_NOSYS on platforms without PSI.

() spawns an xtc_proc(3) that periodically calls () (returns total objects reaped).

struct widget { int id; char name[32]; };

xtc_slab_opts_t opts = XTC_SLAB_OPTS_DEFAULT;
opts.name = "widgets";
opts.obj_size = sizeof(struct widget);
opts.flags = XTC_SLAB_REDZONE | XTC_SLAB_AUDIT;

xtc_slab_t *slab;
xtc_slab_create(&opts, &slab);

struct widget *w = xtc_slab_alloc(slab);
w->id = 42;
strcpy(w->name, "answer");

xtc_slab_free(slab, w);
xtc_slab_destroy(slab);

xtc_mctx(3), xtc_res(3), xtc(7)

Modeled on libumem. Appeared in xtc 0.1.

May 28, 2026 Debian

View the mdoc source