libmizu 0.0.1
Lock-free shared-memory IPC
Loading...
Searching...
No Matches
Data Structures | Macros | Typedefs | Enumerations | Functions
mizu.h File Reference

libmizu public API: SPSC channels and work-stealing task pools between processes on one machine. More...

#include <stddef.h>
#include <stdint.h>
#include <stdatomic.h>
Include dependency graph for mizu.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  mizu_preamble_s
 
struct  mizu_slot_hdr_s
 
struct  mizu_pool_hdr_s
 
struct  mizu_wk_slot_s
 Worker registry slot: two cache lines — admin + owner-written fields on line 0, thief-CAS'd deque_top apart on line 1. More...
 
struct  mizu_sub_slot_s
 
struct  mizu_rs_hdr_s
 Result slot header; the payload framing header sits at offset 24 and payload bytes at 40. More...
 
struct  mizu_entry_hdr_s
 Injection ring / deque entry header; payload framing at offset 24, payload bytes at 40. More...
 
struct  mizu_channel_opts_s
 size-stamped options; mizu_channel_opts_init zeroes + stamps. More...
 
struct  mizu_channel_info_s
 Handle-local + wire-state snapshot. More...
 
struct  mizu_pool_opts_s
 
struct  mizu_task_s
 A task handle: an 8-byte value identifying one result slot at one sequence — 40-bit sequence in the low bits, 24-bit result-slot index in the high (result_slots is capped at 2^24 at create). More...
 
struct  mizu_pool_status_s
 Snapshots. More...
 
struct  mizu_worker_stat_s
 
struct  mizu_sub_stat_s
 
struct  mizu_pool_dump_s
 
struct  mizu_rs_row_s
 One non-FREE result-slot row (a dump's task table). More...
 

Macros

#define MIZU_ATOMIC(T)   _Atomic T
 The wire-format structs carry atomic words.
 
#define MIZU_STATIC_ASSERT   _Static_assert
 
#define MIZU_API
 Export macro.
 
#define MIZU_VERSION_MAJOR   0
 
#define MIZU_VERSION_MINOR   1
 
#define MIZU_VERSION_PATCH   0
 
#define MIZU_MAGIC   0x4D495A43u
 First 64-byte line of every channel region.
 
#define MIZU_ABI_VERSION   1u
 
#define MIZU_DROP_R   0x52u
 The drop's first byte is a wire-format tag, so a foreign child can dispatch on it: MIZU_DROP_R — a native serialize stream (the homogeneous format); MIZU_DROP_SOURCE — UTF-8 source text in the peer's language, the cross-language lingua franca.
 
#define MIZU_DROP_SOURCE   0x53u
 'S'
 
#define MIZU_ENTITY_HOST   0
 Fixed channel layout: preamble (0), rendezvous line (64), one entity block per side (128 host, 192 peer), then the four ring index lines from 256 — one full cache line per shared index.
 
#define MIZU_ENTITY_PEER   1
 
#define MIZU_ENTITY_OFFSET(i)   ((size_t) 128 + 64 * (size_t) (i))
 
#define MIZU_FIXED_LAYOUT_SIZE   ((size_t) 512)
 
#define MIZU_OFF_READY   ((size_t) 64)
 
#define MIZU_OFF_CLOSED   ((size_t) 68)
 
#define MIZU_OFF_PEER_PID   ((size_t) 72)
 
#define MIZU_OFF_FLAGS   ((size_t) 80)
 
#define MIZU_FLAG_SPIN   1u
 pure-spin waiting: consumers never park
 
#define MIZU_ENTITY_EPOCH   0
 
#define MIZU_ENTITY_PARKED   4
 
#define MIZU_ENTITY_REG   8
 
#define MIZU_ENTITY_IDENT   16
 Offset 16 of the 64-byte entity block: the side's identity word (MIZU_IDENT in mizu_ext.h — language byte, reader-capability mask).
 
#define MIZU_OFF_HP_TAIL   ((size_t) 256)
 
#define MIZU_OFF_HP_HEAD   ((size_t) 320)
 
#define MIZU_OFF_PH_TAIL   ((size_t) 384)
 
#define MIZU_OFF_PH_HEAD   ((size_t) 448)
 
#define MIZU_AUX_F_KEEPERLESS   UINT64_C(1)
 Bit 0 of the INLINE aux word: the stager's claim that staging this frame committed no retain-table entry, so a pool collect need not wake the producer's keeper sweep.
 
#define MIZU_STR1_NA   UINT64_MAX
 cannot alias an encoding (0-3)
 
#define MIZU_CE_NATIVE   0u
 The string-encoding byte's values, carried by STR1's aux and the MIZS block's per-string encoding section.
 
#define MIZU_CE_UTF8   1u
 
#define MIZU_CE_LATIN1   2u
 
#define MIZU_CE_BYTES   3u
 
#define MIZU_NA_INT32   INT32_MIN
 The missing-value sentinels of the atomic wire types (the R ABI fixes the bit patterns; a binding of any language writes them without R headers).
 
#define MIZU_NA_INT64   INT64_MIN
 NA_integer64_ sentinel.
 
#define MIZU_NA_REAL_BITS   0x7FF80000000007A2ULL
 NA_real_ (a NaN payload)
 
#define MIZU_ZC_REFCOUNT_OFF   ((size_t) 24)
 Zero-copy view protocol: mizu-owned bytes [24-31] of every MIZU* region header (reserved [24-63] in the layout).
 
#define MIZU_ZC_FLAGS_OFF   ((size_t) 28)
 
#define MIZU_ZC_FLAG_REFHELD   1u
 
#define MIZU_HDR_FLAGS_OFF   ((size_t) 32)
 Region magics (first 4 bytes): atomic vector, string vector, list tree.
 
#define MIZU_HDR_FLAG_S4   1u
 
#define MIZU_HDR_VALID_OFF   ((size_t) 40)
 Header bytes [40-47] and [48-55] are the optional validity-bitmap section of every MIZH and MIZL header (nested MIZL included; MIZS carries its bitmap in the string block instead): an i64 offset and an i64 null count, three states.
 
#define MIZU_HDR_VALID_COUNT   ((size_t) 48)
 
#define MIZU_MIZL_S4   0x40000000
 MIZH (atomic vector): [4-7] i32 wire type, [8-15] i64 element count, [16-23] i64 attrs blob size; bare element bytes at 64, the attrs blob trailing.
 
#define MIZU_MAGIC_VEC   0x4D495A48u
 "MIZH"
 
#define MIZU_MAGIC_STR   0x4D495A53u
 "MIZS"
 
#define MIZU_MAGIC_LIST   0x4D495A4Cu
 "MIZL"
 
#define MIZU_HEADER_SIZE   64
 
#define MIZU_NAME_MAX   30
 fits Windows worst case + NUL; Darwin PSHMNAMLEN
 
#define MIZU_POOL_MAGIC   0x4D495A50u
 "MIZP"
 
#define MIZU_MAX_WORKERS   64
 Parked-worker bitmask width; also the map CLAIM array bound.
 
#define MIZU_ENTRY_RUNNER   1u
 
#define MIZU_INJ_META_SIZE   ((size_t) 128)
 Injection tier metadata (128 B) and control block (192 B) offsets: unrelated hot words, one cache line each.
 
#define MIZU_INJ_TAIL_OFF   ((size_t) 0)
 
#define MIZU_INJ_HEAD_OFF   ((size_t) 64)
 
#define MIZU_TIER_READY_OFF   ((size_t) 0)
 
#define MIZU_TIER_FULL_OFF   ((size_t) 64)
 
#define MIZU_CTRL_SHUTDOWN_OFF   ((size_t) 0)
 
#define MIZU_CTRL_PARKED_OFF   ((size_t) 64)
 
#define MIZU_CTRL_HELP_OFF   ((size_t) 128)
 
#define MIZU_OPEN_VIEW_NOCOUNT   1u
 Heap-only (the stack form stays internal).
 
#define MIZU_CHANNEL_SPIN   MIZU_FLAG_SPIN
 
#define MIZU_TASK_SEQ_BITS   40
 
#define MIZU_TASK_SEQ_MAX   ((UINT64_C(1) << MIZU_TASK_SEQ_BITS) - 1)
 

Typedefs

typedef enum mizu_status_e mizu_status
 The verb result.
 
typedef enum mizu_errcat_e mizu_errcat
 Portable failure categories for MIZU_ERR (the platform layer classifies errno / GetLastError).
 
typedef struct mizu_channel_s mizu_channel
 
typedef struct mizu_pool_s mizu_pool
 
typedef struct mizu_shm_s mizu_shm
 
typedef struct mizu_binding_s mizu_binding
 The binding callbacks struct, taken by pointer at create/attach/join.
 
typedef struct mizu_preamble_s mizu_preamble
 
typedef enum mizu_kind_e mizu_kind
 A 16-byte header then payload bytes, shared by channel slots and pool entries / result slots.
 
typedef struct mizu_slot_hdr_s mizu_slot_hdr
 
typedef enum mizu_type_e mizu_type
 Wire type tags, fixed by the wire format (RAWVEC aux, MIZU* layout headers).
 
typedef struct mizu_pool_hdr_s mizu_pool_hdr
 
typedef struct mizu_wk_slot_s mizu_wk_slot
 Worker registry slot: two cache lines — admin + owner-written fields on line 0, thief-CAS'd deque_top apart on line 1.
 
typedef struct mizu_sub_slot_s mizu_sub_slot
 
typedef struct mizu_rs_hdr_s mizu_rs_hdr
 Result slot header; the payload framing header sits at offset 24 and payload bytes at 40.
 
typedef struct mizu_entry_hdr_s mizu_entry_hdr
 Injection ring / deque entry header; payload framing at offset 24, payload bytes at 40.
 
typedef enum mizu_wk_status_e mizu_wk_status
 
typedef enum mizu_sub_status_e mizu_sub_status
 
typedef enum mizu_rs_status_e mizu_rs_status
 DIED is the reaper's terminal: status-word only, no payload — a reap cannot write payload bytes without racing a live worker's concurrent publish.
 
typedef enum mizu_park_state_e mizu_park_state
 
typedef struct mizu_channel_opts_s mizu_channel_opts
 size-stamped options; mizu_channel_opts_init zeroes + stamps.
 
typedef void(* mizu_obj_sink) (void *ctx, size_t i, void *obj)
 The sink-callback form of recv_batch: each message is handed to sink as it is read, so a binding can anchor every object (a GC protect, a refcount) before the next read allocates — the array form forces a binding to hold n unanchored products across the remaining reads.
 
typedef struct mizu_channel_info_s mizu_channel_info
 Handle-local + wire-state snapshot.
 
typedef struct mizu_pool_opts_s mizu_pool_opts
 
typedef struct mizu_task_s mizu_task
 A task handle: an 8-byte value identifying one result slot at one sequence — 40-bit sequence in the low bits, 24-bit result-slot index in the high (result_slots is capped at 2^24 at create).
 
typedef enum mizu_worker_exit_e mizu_worker_exit
 Worker side: join attaches to token as worker slot (liveness lock before the status CAS; the binding's exec_fn is registered at join).
 
typedef enum mizu_step_result_e mizu_step_result
 One claim at a time, for deterministic in-process harnesses (the pool_pair/pool_step discipline).
 
typedef void *(* mizu_obj_supply) (void *ctx, size_t i)
 The supply-callback form of submit_batch: the binding produces task object i on demand, so it can stage through one reusable wire object instead of pre-building n of them.
 
typedef enum mizu_trace_event_e mizu_trace_event
 Task lifecycle trace hook: per-handle, per-process; NULL removes.
 
typedef void(* mizu_trace_fn) (mizu_trace_event event, uint64_t task_id, void *ctx)
 
typedef struct mizu_pool_status_s mizu_pool_status
 Snapshots.
 
typedef enum mizu_role_e mizu_role
 
typedef struct mizu_worker_stat_s mizu_worker_stat
 
typedef struct mizu_sub_stat_s mizu_sub_stat
 
typedef struct mizu_pool_dump_s mizu_pool_dump
 
typedef struct mizu_rs_row_s mizu_rs_row
 One non-FREE result-slot row (a dump's task table).
 

Enumerations

enum  mizu_status_e {
  MIZU_OK = 0 , MIZU_FULL , MIZU_TIMEOUT , MIZU_CLOSED ,
  MIZU_PEER_GONE , MIZU_ERR
}
 The verb result. More...
 
enum  mizu_errcat_e {
  MIZU_ERRCAT_NONE = 0 , MIZU_ERRCAT_NOSPACE , MIZU_ERRCAT_NOMEMORY , MIZU_ERRCAT_EXISTS ,
  MIZU_ERRCAT_EXHAUSTED , MIZU_ERRCAT_STOPPED , MIZU_ERRCAT_STAGE , MIZU_ERRCAT_INTERRUPTED ,
  MIZU_ERRCAT_OTHER
}
 Portable failure categories for MIZU_ERR (the platform layer classifies errno / GetLastError). More...
 
enum  mizu_kind_e {
  MIZU_KIND_INLINE = 0 , MIZU_KIND_ARENA , MIZU_KIND_SHM_RAW , MIZU_KIND_RAWVEC ,
  MIZU_KIND_SHM_VEC , MIZU_KIND_REF , MIZU_KIND_NIL , MIZU_KIND_STR1 ,
  MIZU_KIND_RAWSPILL
}
 A 16-byte header then payload bytes, shared by channel slots and pool entries / result slots. More...
 
enum  mizu_type_e {
  MIZU_TYPE_LGL = 10 , MIZU_TYPE_INT = 13 , MIZU_TYPE_REAL = 14 , MIZU_TYPE_CPLX = 15 ,
  MIZU_TYPE_STR = 16 , MIZU_TYPE_VEC = 19 , MIZU_TYPE_RAW = 24 , MIZU_TYPE_INT64 = 32
}
 Wire type tags, fixed by the wire format (RAWVEC aux, MIZU* layout headers). More...
 
enum  mizu_wk_status_e {
  MIZU_WK_FREE = 0 , MIZU_WK_CLAIMING , MIZU_WK_LIVE , MIZU_WK_LEAVING ,
  MIZU_WK_REAPING
}
 
enum  mizu_sub_status_e { MIZU_SUB_FREE = 0 , MIZU_SUB_LIVE , MIZU_SUB_REAPING }
 
enum  mizu_rs_status_e {
  MIZU_RS_FREE = 0 , MIZU_RS_PENDING , MIZU_RS_OK , MIZU_RS_ERR ,
  MIZU_RS_CANCEL , MIZU_RS_DIED , MIZU_RS_LOST
}
 DIED is the reaper's terminal: status-word only, no payload — a reap cannot write payload bytes without racing a live worker's concurrent publish. More...
 
enum  mizu_park_state_e { MIZU_WPK_RUNNING = 0 , MIZU_WPK_IDLE , MIZU_WPK_PARKED , MIZU_WPK_WAKING }
 
enum  mizu_worker_exit_e { MIZU_EXIT_SHUTDOWN = 0 , MIZU_EXIT_OWNER_GONE , MIZU_EXIT_RETIRED , MIZU_EXIT_ERROR }
 Worker side: join attaches to token as worker slot (liveness lock before the status CAS; the binding's exec_fn is registered at join). More...
 
enum  mizu_step_result_e { MIZU_STEP_IDLE = 0 , MIZU_STEP_TASK = 1 , MIZU_STEP_SHUTDOWN = -1 , MIZU_STEP_RETIRED = -2 }
 One claim at a time, for deterministic in-process harnesses (the pool_pair/pool_step discipline). More...
 
enum  mizu_trace_event_e {
  MIZU_TRACE_SUBMIT = 0 , MIZU_TRACE_START , MIZU_TRACE_DONE , MIZU_TRACE_ERROR ,
  MIZU_TRACE_DROP , MIZU_TRACE_REHOME
}
 Task lifecycle trace hook: per-handle, per-process; NULL removes. More...
 
enum  mizu_role_e { MIZU_ROLE_CONTROLLER = 0 , MIZU_ROLE_WORKER , MIZU_ROLE_SUBMITTER }
 

Functions

const char * mizu_version (void)
 Library version, "major.minor.patch".
 
mizu_errcat mizu_last_error_category (void)
 Error access.
 
const char * mizu_last_error_message (void)
 
size_t mizu_type_elt_size (int type)
 Element size of an atomic wire type, 0 for non-atomic.
 
mizu_status mizu_shm_create (mizu_shm **out, size_t size)
 
mizu_status mizu_shm_open (mizu_shm **out, const char *name)
 
mizu_status mizu_shm_open_rw (mizu_shm **out, const char *name, int populate)
 
mizu_status mizu_shm_open_view (mizu_shm **out, const char *name)
 
mizu_status mizu_shm_open_view_flags (mizu_shm **out, const char *name, uint32_t flags)
 
void mizu_shm_close (mizu_shm *, int unlink)
 
void * mizu_shm_addr (mizu_shm *)
 
size_t mizu_shm_size (const mizu_shm *)
 
const char * mizu_shm_name (const mizu_shm *)
 
char ** mizu_shm_reap (int *n)
 Reap /mizu_ orphans of dead creators.
 
void mizu_zc_ref (mizu_shm *)
 The consumer side of the zc refcount protocol (header bytes [24-31] of a view-opened region): ref at view wrap, before consumer-done (already performed by mizu_shm_open_view; exported for bindings that map view pages themselves); unref once-only at view release.
 
void mizu_zc_unref (mizu_shm *)
 
uint32_t mizu_zc_refcount (const mizu_shm *)
 
uint32_t mizu_zc_flags (const mizu_shm *)
 
void mizu_zc_flag_refheld (mizu_shm *)
 
void mizu_channel_opts_init (mizu_channel_opts *)
 
mizu_status mizu_channel_create (mizu_channel **out, const mizu_channel_opts *, const mizu_binding *)
 create: host side; writes the preamble, returns the handle.
 
mizu_status mizu_channel_token (const mizu_channel *, char *buf, size_t cap)
 
mizu_status mizu_channel_attach (mizu_channel **out, const char *token, const mizu_binding *)
 
void mizu_channel_drop (const mizu_channel *, const uint8_t **bytes, uint64_t *n)
 The peer bootstrap payload staged at create (the preamble's drop): borrowed bytes, valid until destroy.
 
mizu_status mizu_channel_ready_set (mizu_channel *)
 
mizu_status mizu_channel_ready_wait (mizu_channel *, double timeout_ms)
 
mizu_status mizu_channel_send (mizu_channel *, void *obj)
 send stages obj via the binding's stage_fn: MIZU_OK, MIZU_FULL (ring full — sends never block for ring space; retry or drop is the caller's), MIZU_CLOSED, MIZU_PEER_GONE.
 
mizu_status mizu_channel_send_batch (mizu_channel *, void **objs, size_t n, size_t *accepted_out)
 
mizu_status mizu_channel_recv (mizu_channel *, void **obj_out, double timeout_ms)
 
mizu_status mizu_channel_recv_batch (mizu_channel *, void **objs, size_t cap, size_t *n_out, double timeout_ms)
 
mizu_status mizu_channel_recv_batch_fn (mizu_channel *, size_t cap, size_t *n_out, mizu_obj_sink, void *ctx, double timeout_ms)
 
mizu_status mizu_channel_close (mizu_channel *, double timeout_ms)
 close signals this side's close bit, then waits up to timeout_ms for the peer's close bit or its death — the rendezvous that makes it safe to release the sent-payload pins, since the peer sets its bit only after draining.
 
mizu_status mizu_channel_close_signal (mizu_channel *)
 
int mizu_channel_alive (const mizu_channel *)
 Logically a read; the probe can run survivor cleanup internally.
 
void mizu_channel_destroy (mizu_channel *)
 
void mizu_channel_abandon (mizu_channel *)
 The forked-child teardown: releases only the process-local half of an inherited handle — the child's copies of the mapping and fds and its heap — writing no cross-process word (no close signal, no unlink, no parker or refcount change), so the creating process's handle and the wire state are untouched.
 
mizu_status mizu_channel_info_get (const mizu_channel *, mizu_channel_info *out)
 
mizu_errcat mizu_channel_errcat (const mizu_channel *)
 Handle error access (MIZU_ERR results).
 
const char * mizu_channel_error (const mizu_channel *)
 
void mizu_pool_opts_init (mizu_pool_opts *)
 
static uint64_t mizu_task_seq (const mizu_task *t)
 
static uint32_t mizu_task_rs_index (const mizu_task *t)
 
static mizu_task mizu_task_make (uint64_t seq, uint32_t rs_index)
 
mizu_status mizu_pool_create (mizu_pool **out, const mizu_pool_opts *, const mizu_binding *)
 create: controller side.
 
mizu_status mizu_pool_token (const mizu_pool *, char *buf, size_t cap)
 
mizu_status mizu_pool_ready_wait (mizu_pool *, const uint32_t *slots, size_t n, double timeout_ms)
 
void mizu_pool_destroy (mizu_pool *)
 
void mizu_pool_abandon (mizu_pool *)
 The forked-child teardown: as mizu_channel_abandon — the child's copies of the mapping and fds plus its heap, no cross-process word (no shutdown broadcast, no slot release, no parker or refcount change).
 
mizu_status mizu_pool_attach (mizu_pool **out, const char *token, const mizu_binding *)
 Submitter side: attach joins a live pool from another process, claiming a free submitter slot with its own injection ring and result-slot subrange.
 
mizu_status mizu_pool_worker_join (mizu_pool **out, const char *token, uint32_t slot, const mizu_binding *)
 
mizu_worker_exit mizu_pool_worker_run (mizu_pool *)
 
int mizu_pool_lame_duck (mizu_pool *)
 
mizu_status mizu_pool_leave (mizu_pool *)
 
mizu_status mizu_pool_retire (mizu_pool *, uint32_t slot)
 Controller only: ask one worker to exit cleanly — non-blocking, never preemptive; the worker observes between tasks and releases its slot, and the remaining workers consume its queued work in place.
 
int mizu_pool_step (mizu_pool *, double timeout_ms)
 
mizu_status mizu_pool_submit (mizu_pool *, void *task_obj, mizu_task *out, double timeout_ms)
 submit stages task_obj via the binding's stage_fn and fills *out.
 
mizu_status mizu_pool_submit_batch (mizu_pool *, void **objs, size_t n, mizu_task *out, size_t *n_out, double timeout_ms)
 
mizu_status mizu_pool_submit_batch_fn (mizu_pool *, mizu_obj_supply, void *ctx, size_t n, mizu_task *out, size_t *n_out, double timeout_ms)
 
mizu_status mizu_pool_collect (mizu_pool *, const mizu_task *, void **value_out, double timeout_ms)
 collect waits for the task's terminal state and sets *value_out to the read_fn's product — including for non-OK outcomes, where ctx.outcome (MIZU_RS_ERR / MIZU_RS_CANCEL / MIZU_RS_DIED / MIZU_RS_LOST) lets the read_fn build the binding's error object (a binding re-raises it: the task's own condition, the cancellation, or the worker-death error).
 
mizu_status mizu_pool_collect_any (mizu_pool *, const mizu_task *, size_t n, size_t *index_out, void **value_out, double timeout_ms)
 
mizu_status mizu_pool_collect_all (mizu_pool *, const mizu_task *, size_t n, void **values_out, size_t *err_index_out, size_t *consumed_out, double timeout_ms)
 
mizu_status mizu_pool_collect_all_fn (mizu_pool *, const mizu_task *, size_t n, mizu_obj_sink, void *ctx, size_t *err_index_out, size_t *consumed_out, double timeout_ms)
 The sink-callback form of collect_all: each value is handed to sink as it is claimed (input order when all OK; the first non-OK outcome alone otherwise), so a binding can anchor every object before the next claim's read allocates.
 
mizu_status mizu_pool_set_trace (mizu_pool *, mizu_trace_fn, void *ctx)
 
int mizu_pool_cancel (mizu_pool *, const mizu_task *)
 Advisory and discard-only, never preemptive: a still-queued task is skipped; an executing one runs to completion and its result is dropped.
 
int mizu_pool_task_release (mizu_pool *, const mizu_task *)
 The finalizer release for a task handle that was never collected: a still-pending task is cancelled (as mizu_pool_cancel); a completed (OK/ERR/DIED/LOST) slot is freed, letting the producing worker's keeper sweep drop what the result retained.
 
int mizu_pool_task_state (mizu_pool *, const mizu_task *)
 MIZU_RS_* of a task (informational, racy against slot reuse).
 
mizu_status mizu_pool_stop (mizu_pool *, double timeout_ms)
 Orderly shutdown, controller only: broadcasts shutdown, wakes every parked participant, and cancels all pending tasks (blocked collectors see MIZU_RS_CANCEL), then waits up to timeout_ms for clean worker exits and unlinks the region and liveness files.
 
mizu_status mizu_pool_status_get (const mizu_pool *, mizu_pool_status *out)
 
mizu_status mizu_pool_dump_get (const mizu_pool *, mizu_pool_dump *out)
 
mizu_status mizu_pool_tasks_get (const mizu_pool *, mizu_rs_row *out, uint32_t cap, uint32_t *n_out)
 The dump's task table, paged by the caller: fills up to cap rows in slot order (non-FREE slots only) and sets *n_out to the total non-FREE count, so a short buffer is answered by a second call with a bigger one.
 
mizu_errcat mizu_pool_errcat (const mizu_pool *)
 
const char * mizu_pool_error (const mizu_pool *)
 MIZU_MIZU_H.
 

Detailed Description

libmizu public API: SPSC channels and work-stealing task pools between processes on one machine.

libmizu is a C11 shared-memory IPC library: SPSC channels and a work-stealing task pool between processes on one machine. 64-bit only (the wire formats depend on lock-free 64-bit atomics); Linux requires kernel >= 5.3 (pidfd_open, no fallback).

Three API tiers (the CPython PEP 689 model):

Two versioned contracts:

Conventions:

Not here: the binding seam (mizu_binding, the mizu_stage_* services, result publish, the bytes binding) and the promoted internals (parker, liveness lock, death watch, preamble, map support, mizu_now, the RNG jump kernel) are binding-author surface in mizu_ext.h; the handle struct definitions, spin machinery, and spill/ledger/open-cache internals stay private in src/internal.h.

Macro Definition Documentation

◆ MIZU_ATOMIC

#define MIZU_ATOMIC (   T)    _Atomic T

The wire-format structs carry atomic words.

C++ consumers get std::atomic, layout-compatible with _Atomic on every supported platform; only the C TUs rely on the atomic semantics.

◆ MIZU_API

#define MIZU_API

Export macro.

MIZU_API defaults to empty: static linkage — vendored and amalgamated builds, the first-party packages — needs no macro. Shared-library builds define MIZU_SHARED, plus MIZU_BUILDING when compiling the library itself on Windows.

◆ MIZU_MAGIC

#define MIZU_MAGIC   0x4D495A43u

First 64-byte line of every channel region.

Host-written before spawn, immutable thereafter; validated by the peer before any shared atomic is read or written. "MIZC"

◆ MIZU_DROP_R

#define MIZU_DROP_R   0x52u

The drop's first byte is a wire-format tag, so a foreign child can dispatch on it: MIZU_DROP_R — a native serialize stream (the homogeneous format); MIZU_DROP_SOURCE — UTF-8 source text in the peer's language, the cross-language lingua franca.

The core treats the drop as opaque bytes; the tag is a binding convention. 'R'

◆ MIZU_ENTITY_IDENT

#define MIZU_ENTITY_IDENT   16

Offset 16 of the 64-byte entity block: the side's identity word (MIZU_IDENT in mizu_ext.h — language byte, reader-capability mask).

The host writes it at create, before the token exists; the peer at attach, before ready_set (whose release store orders it for the host's ready_wait acquire). Immutable thereafter.

◆ MIZU_AUX_F_KEEPERLESS

#define MIZU_AUX_F_KEEPERLESS   UINT64_C(1)

Bit 0 of the INLINE aux word: the stager's claim that staging this frame committed no retain-table entry, so a pool collect need not wake the producer's keeper sweep.

Claim-only — the core reads but never verifies it, and cores predating the flag never read INLINE aux at all; clear is always correct (at worst a spurious keeper-sweep wake). Only INLINE carries the claim: every other kind's aux is fully assigned (see the kind docs above).

◆ MIZU_CE_NATIVE

#define MIZU_CE_NATIVE   0u

The string-encoding byte's values, carried by STR1's aux and the MIZS block's per-string encoding section.

The numbering is R's cetype_t, hoisted to the wire contract (bindings pin it with a static assert). An NA string's encoding byte is 0 and its span empty; the validity bit, not the byte, marks it.

◆ MIZU_NA_INT32

#define MIZU_NA_INT32   INT32_MIN

The missing-value sentinels of the atomic wire types (the R ABI fixes the bit patterns; a binding of any language writes them without R headers).

Little-endian throughout, as the whole wire format is. NA_integer_ / NA logical

◆ MIZU_ZC_REFCOUNT_OFF

#define MIZU_ZC_REFCOUNT_OFF   ((size_t) 24)

Zero-copy view protocol: mizu-owned bytes [24-31] of every MIZU* region header (reserved [24-63] in the layout).

[24-27] view refcount, [28-31] flags (bit 0 REFHELD: the identifier escaped by reference, so the death backstop leaks + unlinks instead of force-reclaiming). The producer stores 1 at stage; the consumer adds 1 at wrap before its consumer-done signal; view release subs 1.

◆ MIZU_HDR_FLAGS_OFF

#define MIZU_HDR_FLAGS_OFF   ((size_t) 32)

Region magics (first 4 bytes): atomic vector, string vector, list tree.

Every layout opens with a 64-byte header; bytes [24-63] were reserved (written zero) — the zc protocol owns [24-31], and the two words below are now assigned: the format flags word and the validity section.

Header bytes [32-35] are the format flags word. Bit 0 is the S4 object bit, which the layouts otherwise cannot carry; every other bit is reserved zero. This is a format word, not a negotiation word: a reader rejects a set bit it does not know as a corrupt or newer region (the identity word's reserved bits are the opposite — ignored).

◆ MIZU_HDR_VALID_OFF

#define MIZU_HDR_VALID_OFF   ((size_t) 40)

Header bytes [40-47] and [48-55] are the optional validity-bitmap section of every MIZH and MIZL header (nested MIZL included; MIZS carries its bitmap in the string block instead): an i64 offset and an i64 null count, three states.

{0, 0}: absent — a pre-section region, the core's flat reserve, or a same-language write; the reader's lazy fallback. {0, -1}: known-NA-free (no section materialized). Else the offset of a 64-byte-aligned section: for MIZH a ceil(n / 8)-byte LSB-first bitmap (1 = present, the MIZS string block's convention); for MIZL a table of n {i64 offset, i64 null count} leaf entries, one per directory entry — a VECSXP or STRSXP entry's pair is {0, 0} (the nested header / the string block carries its own), and [48-55] is the total null count across that header's remaining leaves. Reserved-zero means absent, so a pre-dating reader simply never looks; the section needs no capability bit. When the pair is not {0, 0} the section is the authoritative null record: the in-band sentinels are the null-slot fill, and a writer emitting a section writes the wire type's sentinel at every clear bit (DESIGN.md's validity-as-data rules are normative).

◆ MIZU_MIZL_S4

#define MIZU_MIZL_S4   0x40000000

MIZH (atomic vector): [4-7] i32 wire type, [8-15] i64 element count, [16-23] i64 attrs blob size; bare element bytes at 64, the attrs blob trailing.

MIZS (string vector): [4-7] i32 attrs blob size, [8-15] i64 string count, [16-23] i64 string-block byte size; the string block at 64, the attrs blob trailing it. The string block (also the form of an MIZL STRSXP leaf): a ceil(n / 8)-byte validity bitmap, (n + 1) i64 offsets, n encoding bytes (MIZU_CE_*), and the packed string bytes — each section 64-byte aligned from the block start. The first, second and fourth are Arrow large_utf8's three buffers verbatim; the encoding section is R's per-CHARSXP mark. MIZL (list tree): [4-7] i32 element count n, [8-15] i64 attrs blob offset, [16-23] i64 attrs blob size; then n 32-byte directory entries, each { i64 data_offset (64-byte aligned), i64 data_size, i32 sexptype, i32 attrs_size, i64 length }. The entry's data is the bare element bytes (an atomic leaf), a string block (STRSXP), a nested MIZL (VECSXP) or a serialized stream (sexptype 0); the leaf's attrs blob is the last attrs_size bytes of data_size. Bit 30 of the entry's sexptype is the leaf's S4 bit; the remainder is a listed tag — 0 (serialized), the atomic tags, STR, VEC, and 32 (MIZU_TYPE_INT64 is legal on MIZL leaves). Tag 33 is a remote leaf: the column lives in another region and crosses by reference. data_offset / data_size hold the identifier span — the region name, optionally name[i,j,...] with 1-based decimal indices, 1-255 bytes — length and attrs_size describe the referenced column as resolved, the S4 bit is never set, and the validity pair is a {0,0} / {0,-1} claim alone (DESIGN.md's remote-leaf rules are normative).

◆ MIZU_OPEN_VIEW_NOCOUNT

#define MIZU_OPEN_VIEW_NOCOUNT   1u

Heap-only (the stack form stays internal).

create pre-faults on Linux. open maps read-only; open_rw maps writable (populate pre-faults); open_view is the zc consumer open: page 0 RW (the refcount word), the rest read-only — and performs the zc counted add itself, so a binding cannot hold a view mapping without the count. open_view_flags is the flags form: MIZU_OPEN_VIEW_NOCOUNT skips the counted add — the caller then owns the mizu_zc_ref timing and must complete it before its consumer-done signal (a binding whose wrap can fail between map and count opens first and counts at wrap). close unmaps and frees the handle; unlink != 0 also removes the name. On failure these return MIZU_ERR with the category in the thread-local error slot. addr/size/name are borrowed reads, valid until close. caller performs the counted add itself

Typedef Documentation

◆ mizu_status

typedef enum mizu_status_e mizu_status

The verb result.

MIZU_FULL: ring/slot capacity exhausted (try-send). MIZU_TIMEOUT: deadline passed. MIZU_CLOSED: orderly close. MIZU_PEER_GONE: the peer's liveness lock is released (the death verdict; listeners are wake triggers only). MIZU_ERR: a real error — category + message.

◆ mizu_binding

typedef struct mizu_binding_s mizu_binding

The binding callbacks struct, taken by pointer at create/attach/join.

Binding-author surface: the definition, mizu_binding_init, and the built-in bytes binding live in mizu_ext.h.

◆ mizu_kind

typedef enum mizu_kind_e mizu_kind

A 16-byte header then payload bytes, shared by channel slots and pool entries / result slots.

The aux/payload conventions per kind are wire contract (cross-language peers read them), not binding choice:

  • INLINE: a complete serialized stream (len = stream length; aux bit 0 is MIZU_AUX_F_KEEPERLESS, the stager's keeperless claim; all other aux bits zero).
  • ARENA (channel-only): one chunk in the spill arena (aux = chunk offset, byte length as uint64 in the payload).
  • SHM_RAW: name of a region holding the stream (len = name length, payload = name; aux = exact stream length).
  • RAWVEC: bare bytes of an attribute-free atomic vector, slot-resident (len = byte count; aux = wire type tag).
  • RAWSPILL: RAWVEC out of line — len is the byte count and aux & 0xff the wire type tag in both framings. Channel: an arena chunk (aux = type, payload = uint64 offset). Pool: a spill region (aux = type | name length << 8, payload = name).
  • SHM_VEC: name of a region holding an MIZU* layout object (len = name length, payload = name; aux = layout type tag | exact used bytes << 8) — the consumer wraps a zero-copy view.
  • REF: the /mizu_ identifier of an object already in shm (payload = identifier; aux = 0).
  • NIL: immediate empty value — no bytes move.
  • STR1: a length-1 string (bytes in the payload, aux the encoding; MIZU_STR1_NA marks the missing string).

◆ mizu_type

typedef enum mizu_type_e mizu_type

Wire type tags, fixed by the wire format (RAWVEC aux, MIZU* layout headers).

Bindings map their own element types onto these. The numbers are libmizu-owned and frozen from the first release: they descend from R's SEXPTYPE space by history, never by dependency — a future SEXPTYPE joins the wire only by an explicit allocation here, as INT64 = 32 already did.

◆ mizu_wk_slot

typedef struct mizu_wk_slot_s mizu_wk_slot

Worker registry slot: two cache lines — admin + owner-written fields on line 0, thief-CAS'd deque_top apart on line 1.

in_flight_rs/_seq are announced before any claim and read only post-mortem by a reaper serialized by the liveness lock.

◆ mizu_entry_hdr

Injection ring / deque entry header; payload framing at offset 24, payload bytes at 40.

flags bit 0 is MIZU_ENTRY_RUNNER; bits 1-2 are reserved for a future language tag (homogeneous pools in v1). rs_seq binds the entry to its result slot's incarnation (the sequence at submit): a claimed entry whose stamp no longer matches the slot is a zombie left by a dead claimant and never executes.

◆ mizu_rs_status

DIED is the reaper's terminal: status-word only, no payload — a reap cannot write payload bytes without racing a live worker's concurrent publish.

The "worker died" error object is built collect-side, keyed off the status. LOST is the same shape without a death verdict: the task's out-of-line payload vanished before it could run, so the claim performs no force-reclaim of the claimant's lent regions and the collect builds no claimant record.

◆ mizu_channel_opts

size-stamped options; mizu_channel_opts_init zeroes + stamps.

drop is the peer bootstrap payload, copied into the region at create (opaque bytes; its first byte is a MIZU_DROP_* tag by binding convention; the peer's binding reads them after attach).

◆ mizu_obj_sink

typedef void(* mizu_obj_sink) (void *ctx, size_t i, void *obj)

The sink-callback form of recv_batch: each message is handed to sink as it is read, so a binding can anchor every object (a GC protect, a refcount) before the next read allocates — the array form forces a binding to hold n unanchored products across the remaining reads.

Same wait and status discipline as recv_batch (which is a thin adapter over this).

◆ mizu_channel_info

Handle-local + wire-state snapshot.

name is borrowed. Counters are process-local where noted.

◆ mizu_task

typedef struct mizu_task_s mizu_task

A task handle: an 8-byte value identifying one result slot at one sequence — 40-bit sequence in the low bits, 24-bit result-slot index in the high (result_slots is capped at 2^24 at create).

Core-filled at submit; bindings store and pass back by pointer. The 8-byte size lets a binding pack the whole handle into an external-pointer address (zero heap traffic per task). All-zero is the invalid value.

◆ mizu_worker_exit

Worker side: join attaches to token as worker slot (liveness lock before the status CAS; the binding's exec_fn is registered at join).

run is the worker loop shell — claims/steals tasks and invokes exec_fn on this thread — blocking until it returns an exit reason. A nonzero exec_fn return is an infrastructure failure and takes the worker down (MIZU_EXIT_ERROR); a task's own error never reaches run — exec_fn flattens and publishes it through the sink. A retired worker (MIZU_EXIT_RETIRED) lingers as the lifetime anchor for its uncollected results: the binding loops lame_duck on a plain sleep (no unpark can reach a released slot) until it returns nonzero — shutdown or owner death ends the linger; a probe on a handle of any other role returns nonzero without touching it. leave is the clean-exit handshake: an announced in-flight claim (an exec_fn escape left unpublished) fails as DIED there, so an orderly leave after an infrastructure failure never strands a task — the collector's worker-death verdict, no reaper required.

◆ mizu_step_result

One claim at a time, for deterministic in-process harnesses (the pool_pair/pool_step discipline).

Returns MIZU_STEP_TASK after a task, MIZU_STEP_IDLE on timeout, MIZU_STEP_SHUTDOWN on shutdown or owner death, MIZU_STEP_RETIRED on a retire request. An exec_fn infrastructure failure (its nonzero return) or an interrupt abandon records the error on the handle and returns MIZU_STEP_SHUTDOWN — the worker cannot continue; mizu_pool_errcat distinguishes it from a real shutdown.

◆ mizu_obj_supply

typedef void *(* mizu_obj_supply) (void *ctx, size_t i)

The supply-callback form of submit_batch: the binding produces task object i on demand, so it can stage through one reusable wire object instead of pre-building n of them.

Same per-task semantics and wake cadence as the array form (which is a thin adapter over this).

◆ mizu_trace_event

Task lifecycle trace hook: per-handle, per-process; NULL removes.

Worker-side events fire on the worker thread, MIZU_TRACE_SUBMIT on the calling thread. A hook error is an infrastructure failure at its site (on a worker, it takes the worker down) — unlike a task's own error, which is that task's ERR result.

◆ mizu_pool_status

Snapshots.

status reads shm-resident wire state; dump adds handle-local counters (free list, open caches, collect parks) — the cold-path introspection API behind a binding's dump output. Per-slot arrays are indexed by slot; only the first n_workers / n_submitters entries are valid. The per-slot worker states are what a resize scans for free slots. All borrowed; valid until the next call.

Enumeration Type Documentation

◆ mizu_status_e

The verb result.

MIZU_FULL: ring/slot capacity exhausted (try-send). MIZU_TIMEOUT: deadline passed. MIZU_CLOSED: orderly close. MIZU_PEER_GONE: the peer's liveness lock is released (the death verdict; listeners are wake triggers only). MIZU_ERR: a real error — category + message.

◆ mizu_errcat_e

Portable failure categories for MIZU_ERR (the platform layer classifies errno / GetLastError).

Enumerator
MIZU_ERRCAT_NOSPACE 

ENOSPC / ERROR_DISK_FULL.

MIZU_ERRCAT_NOMEMORY 

ENOMEM / commit limit exceeded.

MIZU_ERRCAT_EXISTS 

region name already in use (orphan)

MIZU_ERRCAT_EXHAUSTED 

pool result slots exhausted (submit)

MIZU_ERRCAT_STOPPED 

pool stopped, or its owner died (submit)

MIZU_ERRCAT_STAGE 

the binding's stage_fn returned nonzero

MIZU_ERRCAT_INTERRUPTED 

the binding's check hook returned nonzero

◆ mizu_kind_e

A 16-byte header then payload bytes, shared by channel slots and pool entries / result slots.

The aux/payload conventions per kind are wire contract (cross-language peers read them), not binding choice:

  • INLINE: a complete serialized stream (len = stream length; aux bit 0 is MIZU_AUX_F_KEEPERLESS, the stager's keeperless claim; all other aux bits zero).
  • ARENA (channel-only): one chunk in the spill arena (aux = chunk offset, byte length as uint64 in the payload).
  • SHM_RAW: name of a region holding the stream (len = name length, payload = name; aux = exact stream length).
  • RAWVEC: bare bytes of an attribute-free atomic vector, slot-resident (len = byte count; aux = wire type tag).
  • RAWSPILL: RAWVEC out of line — len is the byte count and aux & 0xff the wire type tag in both framings. Channel: an arena chunk (aux = type, payload = uint64 offset). Pool: a spill region (aux = type | name length << 8, payload = name).
  • SHM_VEC: name of a region holding an MIZU* layout object (len = name length, payload = name; aux = layout type tag | exact used bytes << 8) — the consumer wraps a zero-copy view.
  • REF: the /mizu_ identifier of an object already in shm (payload = identifier; aux = 0).
  • NIL: immediate empty value — no bytes move.
  • STR1: a length-1 string (bytes in the payload, aux the encoding; MIZU_STR1_NA marks the missing string).

◆ mizu_type_e

Wire type tags, fixed by the wire format (RAWVEC aux, MIZU* layout headers).

Bindings map their own element types onto these. The numbers are libmizu-owned and frozen from the first release: they descend from R's SEXPTYPE space by history, never by dependency — a future SEXPTYPE joins the wire only by an explicit allocation here, as INT64 = 32 already did.

Enumerator
MIZU_TYPE_LGL 

int32 logical; INT_MIN is the missing sentinel

MIZU_TYPE_INT 

int32; INT_MIN is the missing sentinel

MIZU_TYPE_REAL 

float64; a specific NaN payload is the sentinel

MIZU_TYPE_CPLX 

interleaved float64 re/im

MIZU_TYPE_STR 

string vector (MIZS layout)

MIZU_TYPE_VEC 

list tree (MIZL layout)

MIZU_TYPE_RAW 

bytes

MIZU_TYPE_INT64 

int64; INT64_MIN is the missing sentinel

◆ mizu_rs_status_e

DIED is the reaper's terminal: status-word only, no payload — a reap cannot write payload bytes without racing a live worker's concurrent publish.

The "worker died" error object is built collect-side, keyed off the status. LOST is the same shape without a death verdict: the task's out-of-line payload vanished before it could run, so the claim performs no force-reclaim of the claimant's lent regions and the collect builds no claimant record.

◆ mizu_worker_exit_e

Worker side: join attaches to token as worker slot (liveness lock before the status CAS; the binding's exec_fn is registered at join).

run is the worker loop shell — claims/steals tasks and invokes exec_fn on this thread — blocking until it returns an exit reason. A nonzero exec_fn return is an infrastructure failure and takes the worker down (MIZU_EXIT_ERROR); a task's own error never reaches run — exec_fn flattens and publishes it through the sink. A retired worker (MIZU_EXIT_RETIRED) lingers as the lifetime anchor for its uncollected results: the binding loops lame_duck on a plain sleep (no unpark can reach a released slot) until it returns nonzero — shutdown or owner death ends the linger; a probe on a handle of any other role returns nonzero without touching it. leave is the clean-exit handshake: an announced in-flight claim (an exec_fn escape left unpublished) fails as DIED there, so an orderly leave after an infrastructure failure never strands a task — the collector's worker-death verdict, no reaper required.

◆ mizu_step_result_e

One claim at a time, for deterministic in-process harnesses (the pool_pair/pool_step discipline).

Returns MIZU_STEP_TASK after a task, MIZU_STEP_IDLE on timeout, MIZU_STEP_SHUTDOWN on shutdown or owner death, MIZU_STEP_RETIRED on a retire request. An exec_fn infrastructure failure (its nonzero return) or an interrupt abandon records the error on the handle and returns MIZU_STEP_SHUTDOWN — the worker cannot continue; mizu_pool_errcat distinguishes it from a real shutdown.

◆ mizu_trace_event_e

Task lifecycle trace hook: per-handle, per-process; NULL removes.

Worker-side events fire on the worker thread, MIZU_TRACE_SUBMIT on the calling thread. A hook error is an infrastructure failure at its site (on a worker, it takes the worker down) — unlike a task's own error, which is that task's ERR result.

Function Documentation

◆ mizu_version()

const char * mizu_version ( void  )

Library version, "major.minor.patch".

Static storage; never freed.

◆ mizu_last_error_category()

mizu_errcat mizu_last_error_category ( void  )

Error access.

Handle verbs record the category + message on the handle; both are valid until the next call on that handle. Handle-free entry points (regions, prune) use a thread-local slot instead.

◆ mizu_shm_reap()

char ** mizu_shm_reap ( int *  n)

Reap /mizu_ orphans of dead creators.

Returns a malloc'd array of malloc'd names (free each, then the array), *n the count; NULL when none — including on platforms that cannot enumerate the shm namespace (Windows, where a mapping cannot outlive its creator).

◆ mizu_zc_ref()

void mizu_zc_ref ( mizu_shm *  )

The consumer side of the zc refcount protocol (header bytes [24-31] of a view-opened region): ref at view wrap, before consumer-done (already performed by mizu_shm_open_view; exported for bindings that map view pages themselves); unref once-only at view release.

flag_refheld marks a region whose identifier is escaping by reference (REF emit).

◆ mizu_channel_create()

mizu_status mizu_channel_create ( mizu_channel **  out,
const mizu_channel_opts *  ,
const mizu_binding *   
)

create: host side; writes the preamble, returns the handle.

token writes the join token ("<pid hex>_<counter hex>") for the peer's attach; returns MIZU_ERR if cap is too small. attach: peer side; validates the preamble (magic + MIZU_ABI_VERSION) before any shared atomic is touched. The peer signals ready_set after attach; the host's ready_wait returns MIZU_OK/MIZU_TIMEOUT.

◆ mizu_channel_drop()

void mizu_channel_drop ( const mizu_channel *  ,
const uint8_t **  bytes,
uint64_t *  n 
)

The peer bootstrap payload staged at create (the preamble's drop): borrowed bytes, valid until destroy.

The peer's binding must consume them (e.g. unserialize the expression) before ready_set — the host holds everything they reference alive exactly until ready.

◆ mizu_channel_send()

mizu_status mizu_channel_send ( mizu_channel *  ,
void *  obj 
)

send stages obj via the binding's stage_fn: MIZU_OK, MIZU_FULL (ring full — sends never block for ring space; retry or drop is the caller's), MIZU_CLOSED, MIZU_PEER_GONE.

send_batch moves up to n objects in one batched tail store and sets *accepted_out — short of n when the ring filled or the channel closed midway (still MIZU_OK; send the next element singly to learn which). recv hands back the read_fn's product in *obj_out: MIZU_OK, MIZU_TIMEOUT, MIZU_CLOSED, MIZU_PEER_GONE. A terminal state is reported only once the ring is drained — the published messages of a closed or dead peer are complete and valid — and MIZU_PEER_GONE is sticky once returned. recv_batch waits for the first message exactly like recv (*n_out is 0 on a terminal status), then drains up to cap already-published messages without waiting further. A batch returns every message it consumed: a read failure on the first message returns MIZU_ERR as recv does, but a failure after it ends the batch early with MIZU_OK and the messages read so far. The failing slot stays at the head, so the next receive reproduces the failure exactly (and consumes the slot if the binding marks it MIZU_READ_CONSUME). MIZU_READ_CONSUME is therefore honoured on a single receive and on a batch's first message only; past that the consume decision defers to the next receive. Callbacks run on the calling thread; the wait parks on the caller's entity.

◆ mizu_channel_close()

mizu_status mizu_channel_close ( mizu_channel *  ,
double  timeout_ms 
)

close signals this side's close bit, then waits up to timeout_ms for the peer's close bit or its death — the rendezvous that makes it safe to release the sent-payload pins, since the peer sets its bit only after draining.

MIZU_OK: rendezvoused, resources released, the region unlinked, and the handle dead (destroy is a no-op after). MIZU_TIMEOUT: the handle stays usable and the rendezvous is retried at destroy. Idempotent. close_signal just sets this side's bit (the peer half of the protocol). After either side signals, sends on both sides return MIZU_CLOSED and receives drain before reporting it. alive is the peer-liveness verdict (lock probe, not the listener flag); a peer that closed but still runs reads as alive. destroy is the GC-finalizer target: idempotent, never blocks; on a handle that never rendezvoused it signals close and releases what the (non-blocking) rendezvous check completes — the death verdict and mizu_shm_reap backstop the rest. Handles are process-private and do not survive fork(): verbs on an inherited handle fail MIZU_ERR; alive, peer_ident, and drop answer empty. destroy on an inherited handle is a contract violation — teardown belongs to the creating process; abandon is the inherited handle's verb.

◆ mizu_channel_abandon()

void mizu_channel_abandon ( mizu_channel *  )

The forked-child teardown: releases only the process-local half of an inherited handle — the child's copies of the mapping and fds and its heap — writing no cross-process word (no close signal, no unlink, no parker or refcount change), so the creating process's handle and the wire state are untouched.

Never blocks; as destroy, it frees the handle and the pointer is dead on return. In the owning process abandon is a contract violation (destroy is the verb).

◆ mizu_channel_errcat()

mizu_errcat mizu_channel_errcat ( const mizu_channel *  )

Handle error access (MIZU_ERR results).

Borrowed; valid until the next call on this handle.

◆ mizu_pool_create()

mizu_status mizu_pool_create ( mizu_pool **  out,
const mizu_pool_opts *  ,
const mizu_binding *   
)

create: controller side.

token as the channel's. ready_wait covers the given worker slots (startup handshake). destroy releases the handle.

◆ mizu_pool_abandon()

void mizu_pool_abandon ( mizu_pool *  )

The forked-child teardown: as mizu_channel_abandon — the child's copies of the mapping and fds plus its heap, no cross-process word (no shutdown broadcast, no slot release, no parker or refcount change).

In the owning process destroy is the verb.

◆ mizu_pool_submit()

mizu_status mizu_pool_submit ( mizu_pool *  ,
void *  task_obj,
mizu_task *  out,
double  timeout_ms 
)

submit stages task_obj via the binding's stage_fn and fills *out.

Submission blocks only on injection-ring space (back-pressure is per-submitter): MIZU_FULL when the ring is still full at the deadline (0 polls; a binding raises its submit-timeout error here). Result-slot exhaustion and a stopped pool / dead owner raise instead: MIZU_ERR with MIZU_ERRCAT_EXHAUSTED / MIZU_ERRCAT_STOPPED. On a worker handle a submit is nested: it pushes onto the worker's own deque (a full deque runs the task inline) and claims a submitter slot on first use. submit_batch applies the same per-task semantics, except that a ring still full at the deadline ends the batch early: MIZU_OK with n_out < n (the single form's MIZU_FULL), the accepted handles valid and collectible.

◆ mizu_pool_collect()

mizu_status mizu_pool_collect ( mizu_pool *  ,
const mizu_task *  ,
void **  value_out,
double  timeout_ms 
)

collect waits for the task's terminal state and sets *value_out to the read_fn's product — including for non-OK outcomes, where ctx.outcome (MIZU_RS_ERR / MIZU_RS_CANCEL / MIZU_RS_DIED / MIZU_RS_LOST) lets the read_fn build the binding's error object (a binding re-raises it: the task's own condition, the cancellation, or the worker-death error).

MIZU_TIMEOUT consumes nothing. A task is collected exactly once: the slot is released as the value is produced. Valid on worker handles too — a nested collect helps (executes/steals) instead of sleeping, so exec_fn reenters from inside collect; on submitter handles (exec == NULL) the wait simply parks. (A binding's collect may omit the pool argument: its task handle carries the pool reference.) collect_any returns the first terminal handle (*index_out, 0-based; ties among already-terminal handles break to the earliest position); the reported handle is consumed, the rest stay collectible. collect_all fills values_out in input order once every task is terminal. On the first non-OK outcome by position it reports that handle only: *err_index_out is its index, the reported handle is consumed (its error object rides read_fn like any value into values_out[err]), and every other handle — the OK results ahead of it included — stays collectible. *err_index_out == n means all OK. A read failure after an all-OK wait returns MIZU_ERR with err_index_out the failing slot's index (unconsumed when retryable) and *consumed_out the number of leading results already handed to the sink / written to values_out — the consumed prefix, for the binding to return or attach; every handle past the prefix stays collectible. *consumed_out is n on a fully collected run, 0 when the run reported a non-OK outcome. MIZU_TIMEOUT consumes nothing: every handle stays valid.

◆ mizu_pool_collect_all_fn()

mizu_status mizu_pool_collect_all_fn ( mizu_pool *  ,
const mizu_task *  ,
size_t  n,
mizu_obj_sink  ,
void *  ctx,
size_t *  err_index_out,
size_t *  consumed_out,
double  timeout_ms 
)

The sink-callback form of collect_all: each value is handed to sink as it is claimed (input order when all OK; the first non-OK outcome alone otherwise), so a binding can anchor every object before the next claim's read allocates.

Same wait and stop-at-error semantics as the array form (which is a thin adapter over this).

◆ mizu_pool_cancel()

int mizu_pool_cancel ( mizu_pool *  ,
const mizu_task *   
)

Advisory and discard-only, never preemptive: a still-queued task is skipped; an executing one runs to completion and its result is dropped.

Returns 1 when this call cancelled the task, 0 when too late (completed, already cancelled, pool gone) — every edge folds into 0, there is no error path. A completed slot is left collectible; releasing a handle that will never be collected is mizu_pool_task_release. A cancelled slot is instead consumed asynchronously by the worker — its publish or claim skip moves the slot CANCEL to FREE without resequencing, so a later collect of the cancelled handle may report the task already collected. A drain after cancel must tolerate that: mizu_pool_task_state distinguishes a drained sibling from a terminal outcome ahead of the collect.

◆ mizu_pool_task_release()

int mizu_pool_task_release ( mizu_pool *  ,
const mizu_task *   
)

The finalizer release for a task handle that was never collected: a still-pending task is cancelled (as mizu_pool_cancel); a completed (OK/ERR/DIED/LOST) slot is freed, letting the producing worker's keeper sweep drop what the result retained.

Returns 1 only when this call cancelled a pending task. Total, no error path: a stale handle, a released pool, or a forked child answers 0.

◆ mizu_pool_stop()

mizu_status mizu_pool_stop ( mizu_pool *  ,
double  timeout_ms 
)

Orderly shutdown, controller only: broadcasts shutdown, wakes every parked participant, and cancels all pending tasks (blocked collectors see MIZU_RS_CANCEL), then waits up to timeout_ms for clean worker exits and unlinks the region and liveness files.

MIZU_TIMEOUT: the workers still exit on their own. The handle is dead afterwards; stopping again is a no-op. destroy on a controller handle broadcasts shutdown the same way, without the wait.

◆ mizu_pool_tasks_get()

mizu_status mizu_pool_tasks_get ( const mizu_pool *  ,
mizu_rs_row *  out,
uint32_t  cap,
uint32_t *  n_out 
)

The dump's task table, paged by the caller: fills up to cap rows in slot order (non-FREE slots only) and sets *n_out to the total non-FREE count, so a short buffer is answered by a second call with a bigger one.

States can move mid-fill — a cold-path snapshot, like dump.