|
libmizu 0.0.1
Lock-free shared-memory IPC
|
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>

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. | |
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:
static inline are internal-only — an FFI cannot reach them.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.
| #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.
| #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.
| #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"
| #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'
| #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.
| #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).
| #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.
| #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
| #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.
| #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).
| #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).
| #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).
| #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 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.
| 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.
| 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:
| 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.
| 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.
| typedef struct mizu_entry_hdr_s 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.
| 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.
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.
| typedef struct mizu_channel_opts_s 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).
| 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).
| typedef struct mizu_channel_info_s mizu_channel_info |
Handle-local + wire-state snapshot.
name is borrowed. Counters are process-local where noted.
| 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.
| 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).
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.
| 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).
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.
| 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).
| typedef enum mizu_trace_event_e 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.
| typedef struct mizu_pool_status_s 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.
| enum 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.
| enum mizu_errcat_e |
Portable failure categories for MIZU_ERR (the platform layer classifies errno / GetLastError).
| enum 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:
| enum 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.
| enum 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.
| enum 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.
| enum 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.
| enum 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.
| const char * mizu_version | ( | void | ) |
Library version, "major.minor.patch".
Static storage; never freed.
| 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.
| 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).
| 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_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.
| 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_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_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.
| 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_errcat mizu_channel_errcat | ( | const mizu_channel * | ) |
Handle error access (MIZU_ERR results).
Borrowed; valid until the next call on this handle.
| 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.
| 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_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_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_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).
| 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.
| 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_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_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.