cwist
Modern C web framework with libttak runtime
Loading...
Searching...
No Matches
gc.h File Reference

Epoch-based garbage collection wrapper. More...

#include <stdbool.h>
#include <stddef.h>
#include <ttak/compat/stdatomic.h>
#include <ttak/mem/epoch_gc.h>
Include dependency graph for gc.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  cwist_gc
 High-level wrapper over libttak's epoch GC. More...
 

Typedefs

typedef struct cwist_gc cwist_gc_t
 High-level wrapper over libttak's epoch GC.
 
typedef atomic_bool cwist_release_guard_t
 One-shot guard ensuring a shared teardown path runs exactly once.
 
typedef void(* cwist_conn_close_fn) (void *handle)
 Full-GC's connection registry: thread/process-exit sweep for resources that aren't plain cwist_alloc() memory – sockets, TLS sessions, protocol-level state – so a worker thread (or the whole process) ending without an explicit destroy-family call still closes them, instead of leaving them for the peer/OS to notice. See docs/GC.md sections 2-3. There is no cwist_conn_t in this codebase (connection lifecycle is protocol-specific – http.c/http2.c/http3.c/ https.c/grpc.c/grpc_client.c each own their own), so this tracks (handle, close_fn) pairs instead of a concrete type.
 

Functions

void cwist_gc (cwist_gc_t *gc, bool manual_rotation)
 Initialize (if needed) and configure the GC context.
 
void cwist_gc_shutdown (cwist_gc_t *gc)
 Shut down and free internal GC state.
 
void cwist_gc_rotate (cwist_gc_t *gc)
 Rotate the GC epoch and reclaim retired nodes.
 
void cwist_gc_auto_rotate (cwist_gc_t *gc, bool enabled)
 Toggle whether the GC context reclaims automatically.
 
bool cwist_gc_auto_rotated (cwist_gc_t *gc)
 Check whether the GC context is currently set to auto-rotate.
 
void cwist_reg_ptr (cwist_gc_t *gc, void *ptr)
 Register a pointer without specifying a size (defaults to 0).
 
void cwist_reg_ptr_sized (cwist_gc_t *gc, void *ptr, size_t size)
 Register a pointer and its size for better accounting.
 
ttak_epoch_gc_t * cwist_gc_raw (cwist_gc_t *gc)
 Obtain the raw libttak epoch GC pointer (advanced usage).
 
void * cwist_ebr_alloc (size_t size)
 Allocate a block meant to be released through cwist_ebr_free().
 
void cwist_ebr_free (void *ptr)
 Defer release of a block shared across threads via epoch reclamation.
 
void cwist_gc_pipeline_tick (void)
 Drive the EBR pipeline: attempt to advance the epoch and run any cwist_ebr_free() callbacks that are now safe to execute.
 
void cwist_full_gc (bool enable)
 Enable or disable full-GC mode process-wide.
 
bool cwist_full_gc_enabled (void)
 Check whether full-GC mode is currently enabled.
 
bool cwist_full_gc_locked (void)
 Check whether the full-GC toggle has been latched (i.e. cwist_full_gc() has been called once already and every further call will be ignored). Diagnostic/testing use.
 
void * cwist_full_gc_guard_page (void)
 Raw pointer to the full-GC toggle's guard page, or NULL if the mmap() backing it failed at process startup. Advanced/testing use only – e.g. to confirm the page is actually read-only after cwist_full_gc() has been called once.
 
void cwist_gc_scope_track (void *ptr)
 Register a cwist_alloc() block with the current thread's pending-sweep list (full-GC mode only).
 
bool cwist_gc_scope_untrack (void *ptr)
 Remove a block from the current thread's pending-sweep list.
 
bool cwist_gc_scope_disown (void *ptr)
 Remove ptr from the current thread's pending-sweep list without freeing it, because ownership is being handed off to other code that will call cwist_free() (or cwist_ebr_free()) on it later, possibly from a different thread.
 
void cwist_gc_scope_flush (void)
 Retire every block still on the current thread's pending-sweep list right now, instead of waiting for the thread to exit.
 
size_t cwist_gc_scope_pending_count (void)
 Number of blocks currently on the calling thread's pending-sweep list. Introspection/testing helper.
 
void cwist_release_guard_init (cwist_release_guard_t *guard)
 Initialize a release guard to its unclaimed state.
 
bool cwist_release_guard_acquire (cwist_release_guard_t *guard)
 Attempt to claim the guard.
 
void cwist_conn_registry_track (void *handle, cwist_conn_close_fn close_fn)
 Register a connection handle for the full-GC exit sweep, owned by the calling thread (full-GC mode only; a no-op otherwise, so callers can call this unconditionally at connection-open time).
 
bool cwist_conn_registry_adopt (void *handle)
 Make the calling thread the owner of a tracked handle.
 
bool cwist_conn_registry_untrack (void *handle)
 Remove a handle from the registry before closing it yourself through the normal explicit path.
 
void cwist_conn_registry_flush (void)
 Close every handle the calling thread owns right now, without waiting for thread exit. Analogous to cwist_gc_scope_flush() but for connections.
 
void cwist_conn_registry_sweep_all (void)
 Sweep every thread's pending-sweep list right now. This is what the process-exit (atexit) hook calls; exposed directly for testing, or for callers that want a deterministic sweep point earlier than actual process exit (e.g. cwist_app_destroy()).
 
size_t cwist_conn_registry_pending_count (void)
 Number of tracked connections the calling thread owns. Introspection/testing helper.
 

Detailed Description

Epoch-based garbage collection wrapper.

Definition in file gc.h.

Typedef Documentation

◆ cwist_conn_close_fn

typedef void(* cwist_conn_close_fn) (void *handle)

Full-GC's connection registry: thread/process-exit sweep for resources that aren't plain cwist_alloc() memory – sockets, TLS sessions, protocol-level state – so a worker thread (or the whole process) ending without an explicit destroy-family call still closes them, instead of leaving them for the peer/OS to notice. See docs/GC.md sections 2-3. There is no cwist_conn_t in this codebase (connection lifecycle is protocol-specific – http.c/http2.c/http3.c/ https.c/grpc.c/grpc_client.c each own their own), so this tracks (handle, close_fn) pairs instead of a concrete type.

Definition at line 301 of file gc.h.

◆ cwist_gc_t

High-level wrapper over libttak's epoch GC.

These helpers keep initialization/destruction scoped to CWIST so applications can toggle GC behavior without touching libttak internals.

◆ cwist_release_guard_t

One-shot guard ensuring a shared teardown path runs exactly once.

Use this when the same release path (e.g. detaching two sibling references and freeing what they both point to) may be entered concurrently from more than one thread, and exactly one of them must win. Initialize with cwist_release_guard_init(); every racer then calls cwist_release_guard_acquire() and only the caller that gets true back performs the detach + free.

Definition at line 276 of file gc.h.

Function Documentation

◆ cwist_conn_registry_adopt()

bool cwist_conn_registry_adopt ( void *  handle)

Make the calling thread the owner of a tracked handle.

Call this when a thread takes over serving a connection another thread tracked (pool resubmit, parked-connection resume, async completion that keeps the connection). Without it, the tracking thread's exit would close a connection the new thread is still using (#345).

Returns
true if handle is tracked and now owned by the caller; false if it is not tracked or full GC is off.
Parameters
handleHandle previously passed to cwist_conn_registry_track().
Returns
true when handle is tracked (and now owned by the caller); false when it is not tracked or full GC is off.

Definition at line 1025 of file gc.c.

References cap, and cwist_full_gc_enabled().

◆ cwist_conn_registry_flush()

void cwist_conn_registry_flush ( void  )

Close every handle the calling thread owns right now, without waiting for thread exit. Analogous to cwist_gc_scope_flush() but for connections.

Ownership follows cwist_conn_registry_adopt(), but a connection this thread tracked and another thread serves without adopting it (a parked or deferred connection) is still owned here, so call this only when none of them can still be in use. The cwist CLI warns on call sites not marked cwist-ack: cwist_conn_registry_flush.

Close every handle the calling thread owns right now, without waiting for thread exit. Analogous to cwist_gc_scope_flush() but for connections.

The registry stays usable afterwards; later tracks work as before.

Definition at line 1041 of file gc.c.

◆ cwist_conn_registry_pending_count()

size_t cwist_conn_registry_pending_count ( void  )

Number of tracked connections the calling thread owns. Introspection/testing helper.

After fork() the child starts with an empty registry: the inherited connections belong to the parent, and a child that exits must not shut them down.

Number of tracked connections the calling thread owns. Introspection/testing helper.

Returns
Number of owned entries; 0 when nothing is tracked.

Definition at line 1060 of file gc.c.

References cap.

◆ cwist_conn_registry_sweep_all()

void cwist_conn_registry_sweep_all ( void  )

Sweep every thread's pending-sweep list right now. This is what the process-exit (atexit) hook calls; exposed directly for testing, or for callers that want a deterministic sweep point earlier than actual process exit (e.g. cwist_app_destroy()).

Sweep every thread's pending-sweep list right now. This is what the process-exit (atexit) hook calls; exposed directly for testing, or for callers that want a deterministic sweep point earlier than actual process exit (e.g. cwist_app_destroy()).

Intended for process-exit paths. Each handle is removed before it is closed, so racing sweeps (atexit vs. a thread's own exit) close it once.

Definition at line 1052 of file gc.c.

References cap.

◆ cwist_conn_registry_track()

void cwist_conn_registry_track ( void *  handle,
cwist_conn_close_fn  close_fn 
)

Register a connection handle for the full-GC exit sweep, owned by the calling thread (full-GC mode only; a no-op otherwise, so callers can call this unconditionally at connection-open time).

The registry is one process-wide table. Each handle has an owner thread; that thread's exit sweep (or cwist_conn_registry_flush()) closes it. The owner is the tracking thread until cwist_conn_registry_adopt() moves it.

Parameters
handleOpaque connection handle, passed back to close_fn.
close_fnCalled with handle to close/tear it down; must be safe to call from whichever thread ends up sweeping it (the owning thread at its own exit, or any thread running the atexit sweep at process exit). It is called with no registry lock held and may track or untrack other handles.

Register a connection handle for the full-GC exit sweep, owned by the calling thread (full-GC mode only; a no-op otherwise, so callers can call this unconditionally at connection-open time).

No-op unless full-GC mode is enabled. Best-effort: if the table cannot grow, the handle is dropped rather than failing the caller. Tracking a handle that is already tracked updates its close_fn and makes the caller its owner.

Parameters
handleResource handle to close later (e.g. socket, TLS session).
close_fnCallback invoked with handle during a sweep or flush.

Definition at line 984 of file gc.c.

References cap, and cwist_full_gc_enabled().

◆ cwist_conn_registry_untrack()

bool cwist_conn_registry_untrack ( void *  handle)

Remove a handle from the registry before closing it yourself through the normal explicit path.

Works from any thread, whichever thread owns the handle: a connection is usually tracked on the thread that accepted it but closed on another one (async completion, keep-alive resubmit, parked-connection expiry), and a handle left behind would be closed a second time by a sweep (#344). Untrack must still happen before the handle is freed, and only one party may close it; coordinate racing closers yourself (e.g. cwist_release_guard_t).

Returns
true if handle was pending and has been removed; false if it was never tracked or already swept. Either way the caller should proceed to close it.

Remove a handle from the registry before closing it yourself through the normal explicit path.

Parameters
handleHandle previously passed to cwist_conn_registry_track().
Returns
true when found and removed; false otherwise.

Definition at line 1010 of file gc.c.

References cap.

Referenced by cwist_https_close_connection().

◆ cwist_ebr_alloc()

void * cwist_ebr_alloc ( size_t  size)

Allocate a block meant to be released through cwist_ebr_free().

Identical to cwist_alloc() today: a freshly allocated block is not yet shared, so nothing needs epoch protection until it is published to other threads. The distinct name exists to mark call sites that pair with cwist_ebr_free() instead of cwist_free().

Parameters
sizeNumber of bytes to allocate.
Returns
Newly allocated block, or NULL on failure.

Allocate a block meant to be released through cwist_ebr_free().

Parameters
sizeNumber of bytes to allocate.
Returns
Newly allocated block, or NULL on failure.

Definition at line 331 of file gc.c.

References cwist_alloc().

◆ cwist_ebr_free()

void cwist_ebr_free ( void *  ptr)

Defer release of a block shared across threads via epoch reclamation.

Unlike cwist_free(), this does not release ptr immediately. It hands the pointer to libttak's EBR (ttak_epoch_retire) so the actual free only runs once every thread that might still be inside a ttak_epoch_enter() / ttak_epoch_exit() critical section touching ptr has left it.

Callers on the reading side MUST wrap their access to the shared pointer in ttak_epoch_enter()/ttak_epoch_exit() for this guarantee to hold; this function alone does not protect readers that skip that discipline.

The actual free only happens once something calls ttak_epoch_reclaim() (see cwist_gc_pipeline_tick()) and observes it is safe.

Parameters
ptrBlock previously returned by cwist_ebr_alloc() (or cwist_alloc()).

Defer release of a block shared across threads via epoch reclamation.

Parameters
ptrBlock to retire; a no-op when NULL.

Definition at line 350 of file gc.c.

◆ cwist_full_gc()

void cwist_full_gc ( bool  enable)

Enable or disable full-GC mode process-wide.

Hardened, boot-time-only setter: the first call wins and is latched in; every later call – from any thread, deliberate re-invocation or otherwise – is a silent no-op, and the backing storage is mprotect()'d read-only after that first call so a raw memory-corruption write can't flip it either. See gc.c's cwist_full_gc_guard_t for the full threat model this defends against.

Parameters
enableWhen true, cwist_alloc() starts registering blocks with the per-thread pending-sweep list and cwist_free() starts unregistering them; a worker thread that exits without freeing everything it allocated has the remainder swept via cwist_ebr_free() automatically.

Enable or disable full-GC mode process-wide.

The first caller stores enable into the guard page, marks the page locked, and mprotect()s it read-only; every later call is a silent no-op. Fails safe (no-op) when the guard page was never mapped. Also toggles auto-rotation on the process-wide full-GC instance.

Parameters
enabletrue to enable full-GC mode, false to claim-and-disable.

Definition at line 483 of file gc.c.

References cwist_gc_auto_rotate().

◆ cwist_full_gc_enabled()

bool cwist_full_gc_enabled ( void  )

Check whether full-GC mode is currently enabled.

Check whether full-GC mode is currently enabled.

Returns
Current enabled state; false when the guard page was never mapped.

Definition at line 515 of file gc.c.

Referenced by cwist_async_defer(), cwist_conn_registry_adopt(), cwist_conn_registry_track(), cwist_h2_async_queue_enqueue(), cwist_http_async_disown_session(), cwist_https_close_connection(), cwist_https_receive_request(), cwist_io_queue_create(), cwist_io_queue_run(), cwist_io_queue_submit(), and cwist_scheduler_create().

◆ cwist_full_gc_guard_page()

void * cwist_full_gc_guard_page ( void  )

Raw pointer to the full-GC toggle's guard page, or NULL if the mmap() backing it failed at process startup. Advanced/testing use only – e.g. to confirm the page is actually read-only after cwist_full_gc() has been called once.

Raw pointer to the full-GC toggle's guard page, or NULL if the mmap() backing it failed at process startup. Advanced/testing use only – e.g. to confirm the page is actually read-only after cwist_full_gc() has been called once.

Returns
Pointer to the guard page, or NULL if mmap() failed at startup.

Definition at line 533 of file gc.c.

◆ cwist_full_gc_locked()

bool cwist_full_gc_locked ( void  )

Check whether the full-GC toggle has been latched (i.e. cwist_full_gc() has been called once already and every further call will be ignored). Diagnostic/testing use.

Check whether the full-GC toggle has been latched (i.e. cwist_full_gc() has been called once already and every further call will be ignored). Diagnostic/testing use.

Returns
true once cwist_full_gc() has run its claiming path exactly once.

Definition at line 524 of file gc.c.

◆ cwist_gc()

void cwist_gc ( cwist_gc_t *  gc,
bool  manual_rotation 
)

Initialize (if needed) and configure the GC context.

Parameters
gcTarget context.
manual_rotationWhen true, force manual rotations instead of the background thread.

Initialize (if needed) and configure the GC context.

Parameters
gcGC context owned by the caller.
manual_rotationWhen true, keep epoch advancement under explicit caller control.

Definition at line 173 of file gc.c.

References cwist_gc::impl, and cwist_gc::initialized.

◆ cwist_gc_auto_rotate()

void cwist_gc_auto_rotate ( cwist_gc_t *  gc,
bool  enabled 
)

Toggle whether the GC context reclaims automatically.

Parameters
gcTarget context.
enabledWhen true, mark the context as auto-rotated (full-GC mode).

Toggle whether the GC context reclaims automatically.

Parameters
gcGC context to enable auto-rotation.

Definition at line 212 of file gc.c.

References cwist_gc::auto_rotated, and cwist_gc::initialized.

Referenced by cwist_full_gc().

◆ cwist_gc_auto_rotated()

bool cwist_gc_auto_rotated ( cwist_gc_t *  gc)

Check whether the GC context is currently set to auto-rotate.

Check whether the GC context is currently set to auto-rotate.

Definition at line 222 of file gc.c.

References cwist_gc::auto_rotated.

◆ cwist_gc_pipeline_tick()

void cwist_gc_pipeline_tick ( void  )

Drive the EBR pipeline: attempt to advance the epoch and run any cwist_ebr_free() callbacks that are now safe to execute.

Call this periodically (e.g. once per event-loop tick) from a single well-known place; nothing retired via cwist_ebr_free() is ever actually released unless this runs.

Drive the EBR pipeline: attempt to advance the epoch and run any cwist_ebr_free() callbacks that are now safe to execute.

Definition at line 358 of file gc.c.

◆ cwist_gc_raw()

ttak_epoch_gc_t * cwist_gc_raw ( cwist_gc_t *  gc)

Obtain the raw libttak epoch GC pointer (advanced usage).

Intended for registering pointers that carry a libttak block header (ttak_mem_alloc_safe() et al.) via ttak_epoch_gc_register(): such blocks are released by ttak_mem_free() when the context is destroyed. Use cwist_reg_ptr() for cwist_alloc() blocks instead.

Obtain the raw libttak epoch GC pointer (advanced usage).

Use this to register pointers that carry a libttak block header (ttak_mem_alloc_safe() et al.) via ttak_epoch_gc_register(): such blocks keep libttak's native teardown semantics and are released by ttak_mem_free() at destroy. cwist_reg_ptr() is the right API for cwist_alloc() blocks instead.

Parameters
gcGC wrapper owned by CWIST.
Returns
Raw libttak GC handle, or NULL when the wrapper is unavailable.

Definition at line 321 of file gc.c.

References cwist_gc::impl, and cwist_gc::initialized.

◆ cwist_gc_rotate()

void cwist_gc_rotate ( cwist_gc_t *  gc)

Rotate the GC epoch and reclaim retired nodes.

Rotate the GC epoch and reclaim retired nodes.

Parameters
gcGC context to rotate.

Definition at line 203 of file gc.c.

References cwist_gc::impl, and cwist_gc::initialized.

◆ cwist_gc_scope_disown()

bool cwist_gc_scope_disown ( void *  ptr)

Remove ptr from the current thread's pending-sweep list without freeing it, because ownership is being handed off to other code that will call cwist_free() (or cwist_ebr_free()) on it later, possibly from a different thread.

Without this call, a block allocated by one unit of work (e.g. a queued job) and stored somewhere for a later unit of work to release would be auto-swept as soon as the allocating unit of work finishes – the sweep logic cannot otherwise tell "nobody will ever free this" apart from "someone else will free this later". Call cwist_gc_scope_disown() at the point of handoff, before the pointer becomes visible to whatever will eventually free it.

This is exactly cwist_gc_scope_untrack() under a name that documents the handoff use case; the two are interchangeable.

Returns
true if ptr was pending and has been removed; false if it was never tracked (full-GC mode was off at alloc time, or it was already disowned/freed).

Remove ptr from the current thread's pending-sweep list without freeing it, because ownership is being handed off to other code that will call cwist_free() (or cwist_ebr_free()) on it later, possibly from a different thread.

Parameters
ptrBlock to untrack.
Returns
true when ptr was tracked and removed; false otherwise.

Definition at line 766 of file gc.c.

References cwist_gc_scope_untrack().

Referenced by cwist_async_defer(), cwist_h2_async_queue_enqueue(), cwist_http_async_disown_session(), cwist_https_receive_request(), cwist_io_queue_create(), cwist_io_queue_submit(), and cwist_scheduler_create().

◆ cwist_gc_scope_flush()

void cwist_gc_scope_flush ( void  )

Retire every block still on the current thread's pending-sweep list right now, instead of waiting for the thread to exit.

"Every block" means every block, live or not: the flush cannot tell a forgotten allocation from one that is still in use, so it retires both.

Contract. Call this only at a point where the calling thread holds no tracked block that anything will touch again:

  • OK: the end of a self-contained job on a dedicated worker thread, after everything the job hands on has been disowned (cwist_gc_scope_disown()) or handed to a CWIST API that disowns it (e.g. cwist_async_respond_with()).
  • Not OK: inside a request handler or middleware (the response is still being built and sent after next() returns), or on any thread that serves connections (HTTP/2 session state and other per-connection objects live across requests on that thread).

Reclamation. Retired blocks go to cwist_ebr_free(), and the flush then drives reclamation itself (ttak_epoch_reclaim()), so they are freed as soon as no thread is inside an older epoch, normally before this call returns. The thread-exit sweep does the same. Request-serving threads never enter an epoch, so reclaim treats a retired block as unreferenced even if a thread is still using it: a block flushed while still in use is freed while still in use. (Before #347 nothing drove reclaim unless the app ran an io_queue, so misuse leaked instead of crashing.)

Misuse is a use-after-free, so the cwist CLI (cwist audit, cwist watcher) warns on every call site that is not marked cwist-ack: cwist_gc_scope_flush. See docs/GC.md, "Explicit flushes and reclamation", and c4punks/CWIST#347.

Retire every block still on the current thread's pending-sweep list right now, instead of waiting for the thread to exit.

Each tracked block is handed to cwist_ebr_free(), so reclamation is deferred until no thread can still be reading inside an epoch.

Definition at line 776 of file gc.c.

Referenced by cwist_io_queue_run().

◆ cwist_gc_scope_pending_count()

size_t cwist_gc_scope_pending_count ( void  )

Number of blocks currently on the calling thread's pending-sweep list. Introspection/testing helper.

Number of blocks currently on the calling thread's pending-sweep list. Introspection/testing helper.

Returns
Number of pending entries; 0 when nothing is tracked.

Definition at line 784 of file gc.c.

◆ cwist_gc_scope_track()

void cwist_gc_scope_track ( void *  ptr)

Register a cwist_alloc() block with the current thread's pending-sweep list (full-GC mode only).

Called by cwist_alloc() itself; not meant to be called directly.

Register a cwist_alloc() block with the current thread's pending-sweep list (full-GC mode only).

Best-effort: on allocation failure the block is left untracked rather than failing the caller's allocation. Duplicate pointers are stored once.

Parameters
ptrBlock to track; a no-op when NULL.

Definition at line 707 of file gc.c.

References cap.

◆ cwist_gc_scope_untrack()

bool cwist_gc_scope_untrack ( void *  ptr)

Remove a block from the current thread's pending-sweep list.

Called by cwist_free() itself before it releases ptr, so a block that was freed explicitly is never swept a second time at thread exit.

Returns
true if ptr was pending (and has been removed); false if it was never tracked (e.g. it came from cwist_strdup()/cwist_realloc() instead of cwist_alloc(), or full-GC mode was off at alloc time). Either way the caller should proceed to free ptr normally.

Remove a block from the current thread's pending-sweep list.

Used when the caller hands ownership elsewhere (e.g. frees through a different path); the block is removed from this thread's pending set and will not be epoch-retired by a later flush.

Parameters
ptrBlock to untrack.
Returns
true when ptr was tracked and removed; false otherwise.

Definition at line 734 of file gc.c.

References cap.

Referenced by cwist_gc_scope_disown().

◆ cwist_gc_shutdown()

void cwist_gc_shutdown ( cwist_gc_t *  gc)

Shut down and free internal GC state.

Releases every block still registered through cwist_reg_ptr() / cwist_reg_ptr_sized() with cwist_free(); blocks registered directly with ttak via cwist_gc_raw() are released by libttak instead.

Shut down and free internal GC state.

Blocks still registered through cwist_reg_ptr()/cwist_reg_ptr_sized() are detached from the libttak tree and released with cwist_free() first; anything registered directly with ttak via cwist_gc_raw() is left for ttak_epoch_gc_destroy() to release with ttak_mem_free().

Parameters
gcGC context to shut down.

Definition at line 192 of file gc.c.

References cwist_gc::impl, and cwist_gc::initialized.

◆ cwist_reg_ptr()

void cwist_reg_ptr ( cwist_gc_t *  gc,
void *  ptr 
)

Register a pointer without specifying a size (defaults to 0).

Hands ownership of the block to the context: cwist_gc_shutdown() releases it with cwist_free(), and an explicit cwist_free() detaches it first. The pointer must come from CWIST's allocator (cwist_alloc() and family); see cwist_reg_ptr_sized() for the full contract.

Register a pointer without specifying a size (defaults to 0).

See cwist_reg_ptr_sized() for the full contract: registering hands ownership of the block to the context, which releases it with cwist_free() at cwist_gc_shutdown().

Parameters
gcGC context that tracks the pointer.
ptrPointer to retire through the epoch GC.

Definition at line 236 of file gc.c.

References cwist_reg_ptr_sized().

◆ cwist_reg_ptr_sized()

void cwist_reg_ptr_sized ( cwist_gc_t *  gc,
void *  ptr,
size_t  size 
)

Register a pointer and its size for better accounting.

The pointer must be releasable with cwist_free() (i.e. come from CWIST's allocator: cwist_alloc() and family). The wrapper keeps its own registry of such pointers so that cwist_gc_shutdown() can detach them from libttak's mem_tree and release them with cwist_free(); libttak's own destroy-time pass frees with ttak_mem_free() and aborts on a cwist_alloc block, which carries no ttak block header. Pointers allocated directly from libttak (ttak_mem_alloc_safe()) keep libttak's teardown semantics instead: register them through cwist_gc_raw() with ttak_epoch_gc_register().

After registration the context owns the block. An explicit cwist_free() detaches it automatically (staying correct, just unregistering early), and registering the same pointer with another context moves tracking there.

Register a pointer and its size for better accounting.

The pointer must be releasable with cwist_free() (i.e. come from CWIST's allocator: cwist_alloc() and family). The wrapper records the pointer in its own registry so that cwist_gc_shutdown() can detach it from libttak's mem_tree and release it with cwist_free(); libttak's destroy-time pass frees with ttak_mem_free(), which aborts on headerless cwist_alloc blocks. Pointers allocated directly from libttak (ttak_mem_alloc_safe()) must NOT go through here; register them with the raw context instead — ttak_epoch_gc_register(cwist_gc_raw(gc), ptr, size) — so libttak's own teardown releases them.

Ownership: after registration the context owns the block and will free it at shutdown. An explicit cwist_free() first detaches it automatically; registering the same pointer with another context moves tracking there.

Parameters
gcGC context that tracks the pointer.
ptrPointer to retire through the epoch GC.
sizeOptional size hint associated with ptr.

Definition at line 261 of file gc.c.

References cwist_gc::impl, and cwist_gc::initialized.

Referenced by cwist_reg_ptr().

◆ cwist_release_guard_acquire()

bool cwist_release_guard_acquire ( cwist_release_guard_t *  guard)

Attempt to claim the guard.

Returns
true exactly once across all racing callers; false to every other caller (including ones arriving after the winner finishes).

Attempt to claim the guard.

Parameters
guardGuard shared by every racing caller.
Returns
true for exactly one caller across all racers; false otherwise.

Definition at line 376 of file gc.c.

◆ cwist_release_guard_init()

void cwist_release_guard_init ( cwist_release_guard_t *  guard)

Initialize a release guard to its unclaimed state.

Initialize a release guard to its unclaimed state.

Parameters
guardGuard to initialize.

Definition at line 366 of file gc.c.