tiny.mprompt
Overview · API · Code relationships · Verification · Audit
Overview
The package lets a Zig function stop partway through, hand control back to an earlier point on the call stack, and later continue from where it stopped, with a value passed in. Capturing a running computation's stack segment and resuming it later gives the package delimited continuations, and on top of them typed algebraic effect handlers. It has two layers: functions with the C calling convention that pass raw pointers, and a typed Zig API whose value types the compiler checks. The runtime keeps each thread's running computations, cached stacks and handlers in per-thread state.
Generators, workers that wait for their next request, backtracking searches, and interpreters that pause to ask their host for a value all need a computation that stops in the middle and continues later. The code that started such a computation needs to learn whether it finished or paused, and then continue it once, continue it more than once, or abandon it.
A paused computation needs every frame between the pause and its starting point kept alive, with its locals and return addresses, and an ordinary call stack discards those frames when the function returns. Continuing twice from one pause needs the frames as they were at the pause, and running the rest of the computation the first time overwrites them. Each paused computation needs a stack of its own, and programs hold many at once: a test keeps 16 workers paused, and the profiling workload runs 10,000. So an idle stack has to cost little memory, and a busy one has to stay within a bound. Moving from one stack to another means saving and restoring the processor's registers, which takes code written for each processor.
Daan Leijen's paper Implementing Algebraic Effects in C and his libmprompt library, from the Koka project, implement multi-prompt delimited continuations and algebraic effect handlers. The package keeps libmprompt's execution model: code runs on stacks of its own, suspends to a marked point, and resumes through a handle, and handlers move control the same way. The package's reference benchmark reruns libmprompt's reference workloads at release sizes, and a test runs the effect counter at the upstream debug workload size.
Each resumable computation runs on a stack of its own, a stacklet, reserved at a fixed size (8 MiB by default) with an unmapped gap at each end, and its pages become usable only as the stack grows into them. The runtime marks the point where a computation enters its stacklet as the computation's prompt, the computation suspends back to that point, and the stacklet keeps the suspended frames as they were. Suspending hands back a handle to the suspended computation, a resumption. Resuming the resumption makes the suspending call return the value passed in. One form is a resumption that runs once (one-shot): it returns control to the point where the computation suspended, and the computation continues on the same stacklet with no copy. The other form is a resumption that may run more than once (multi-shot): it keeps a reference count, and the runtime saves the stacklet's segments to the heap and restores them when it needs to, so the handle can resume again and again. Duplicating such a handle adds one reference and copies no stack memory at that moment. The Zig API keeps ownership explicit: run and SuspendedRun keep the body's result where the caller reads it, and a caller that abandons a paused run drops its handle. The Zig API has the compiler check the type of every value that crosses between stacks, and error unions pass through unchanged. Stacklet memory is bounded: the process takes stacklets from shared pool regions of at most 32,000 blocks each, 256 GiB of address space by default, and each thread keeps at most four freed stacklets for reuse by default. The stack switch exists for x86_64 and aarch64 targets other than Windows, and the package compiles only for 64-bit targets, because every stacklet reserves address space of its own.
Definitions
Actions
Public operations.
Continuation: Returns the typed handle type that ayieldWithhandler gets for the paused rest of the body, for a handler that uses it to continue the paused body with its answer.SuspendedRun: Returns a struct type that holds a context pointer, storage for the body's result, and a done marker, for a caller that starts a body that may pause and hand control back, then continues it later from its own loop, as a scheduler does with workers or the Chic host does with an interpreter turn.run: A caller runs the body to its end in one call, and a handler answers each pause before the body goes on.SuspendedPrompt: Returns the typed handle type for a body that paused inside aSuspendedRun.yieldWith: Suspends the body atpromptand runshandler(continuation, handler_context, value)on the stack of the code that calledrun, so that a handler outside the body computes its next value, as a generator hands out each value or a worker asks for input.PromptOutcome: Returns a tagged union type with two cases: the body returned, or the body paused.suspendPrompt: Suspends the body atprompt, so the pendingstartorcontinueWithcall returns.suspendedwith a handle, for a body started bySuspendedRunthat pauses and hands control back to the code that started or last continued it.runWithoutContext: Runsbody(prompt)the wayrundoes, with no context argument, so a caller whose body needs no context skips the pointer.forward: Returns a clause that passes the operation to the next enclosing handler of the same effect, so an inner handler that answers some operations of an effect lets an outer handler answer the rest.operation: Returns the signature of one operation with argument typeArgand result typeResult, so a caller writes one per field of anEffectDefinitionspec's.operations.processAllocator: Returns the process-wide allocator of thesyspackage, so the effect layer allocates its resumption records from the same allocator as the runtime.promptCreate: Returns a new prompt with one owner, its own stacklet, and no saved registers, so a caller creates a prompt ahead of the call that enters it.promptEnter: Switches top's stacklet and callsfun(p, arg)there, so a caller runsfunon a prompt created earlier withpromptCreate.captureBacktrace: Fillsbufferwith the return addresses of the calling thread's current stack and returns how many it wrote, so a caller records the return addresses of its current stack for a diagnostic.configDefault: Returns aConfigwith every field at its default, so a caller starts from the defaults and changes only the fields it needs.init: Initializes the runtime fromcfg, or from the defaults whencfgis null, so a program calls it once before creating any prompt to replace the default configuration.promptParent: Returns the next active prompt outward fromp, or the innermost active prompt whenpis null, so a caller walks the thread's active prompts outward one step per call, as the runtime does to check that a suspend targets an active prompt.promptTop: Returns the calling thread's innermost active prompt, or null when no prompt is active, so a caller finds the innermost prompt its code runs under without being handed it.resumeDrop: Gives up the handle without resuming, for a caller that abandons suspended code it will not continue.resumeDup: Adds one reference to a multi-shot handle and returns the same handle, or returns null for a one-shot handle, so a caller takes one extra reference for each extra resume.resumePrompt: Switches back into the suspended code so that itsyieldPromptcall returnsarg, for a yield function or code that kept a resumption to continue the suspended code with a value.resumeResumeCount: Returns the number of resumes of a multi-shot handle, or 0 for a one-shot handle, so a caller reads how many times a multi-shot handle has been resumed so far.resumeShouldUnwind: Returns 1 for a multi-shot handle that holds the last reference and has never been resumed, and 0 otherwise, one-shot handles included, for the effect layer to choose between unwinding the suspended body and dropping one reference before releasing a resumption.resumeTailPrompt: Resumes likeresumePrompt, but the resumed code's next suspend or return jumps to the point that called the yield function, so this call does not return to its caller.yieldPrompt: Suspends the calling code together withpand each nested active prompt, so code running under a prompt suspends back to the point that entered the prompt and hands a resumption to a function there, as a worker does while it waits for its request.EffectContinuation: Returns the continuation type for clause kindsscoped_once,scoped,onceandmulti, so a typed clause that may keep the body waiting receives one and resumes the body with the operation's result.on: Returns a clause that answers an operation withhandlerunder clause kindkind, so a caller writes one per operation in the clauses passed to a typedhandle.prompt: Creates a prompt and enters it withfunandarg, which ispromptCreatefollowed bypromptEnter, so a caller runs a C-convention function on a new stacklet in one call.resumeMulti: Returns a multi-shot handle for the same suspend, so a yield function converts its handle before resuming the same suspend more than once.EffectDefinition: Returns a type for one effect so a caller declares an effect once in Zig, then performs and handles its operations with checked types and no pointer casts.
Types and contracts
Public types and contracts.
Config: Holds the runtime's tuning values with a C layout, and every field has a default.Prompt: The runtime's record for one prompt: its stacklet, its links to other prompts, its reference count, and the registers saved for its entry and its last suspend.Resume: An opaque handle to a suspended prompt, so a yield function receives one and resumes or drops it, and code that suspends to its caller hands it back as the caller's result.StartFn: Function type a new prompt runs first, with the C calling convention, so a caller passes one topromptorpromptEnterto run it on a prompt's stacklet.YieldFn: Function typeyieldPromptruns after the suspend, with the C calling convention, so a caller writes one to receive the resumption when code suspends.
Namespaces
Public namespaces.
zig_api: A typed Zig layer over the package's stack-switching runtime runs a function on a stack of its own and returns the function's result as a Zig value.effect: Code in a body makes a named request, and the nearest enclosing code registered for that request answers it and decides whether the body continues, how often, and with what value: algebraic effect handlers, built on the package's stack-switching runtime.
Code relationships
Direct static dependencies extracted from parsed source by semantic graph analysis.
Uses: tiny.bench, tiny.hypothesis, tiny.sys
Used by: None
Verification
No verification records are cataloged for this module in this build.
Audit
| Evidence | Value |
|---|---|
| Source | lib/mprompt/src/root.zig |
| Definitions | 37 of 37 documented |
| Members | 0 of 0 documented |
| Public names | 37 API, 78 indexed |
| Version | 26.7.0 |
| Revision | daab053ee433 |