Skip to content

Execution

Invocation entry, continuation scheduling, task trees, and cancellation.

Updated View as Markdown

Atoll lowers suspendable code into continuation-passing form. A generated scheduler, driven by the host trampoline, advances ready work until the root task finishes, an asynchronous operation must be polled, or execution yields cooperatively.

The result is stackful source semantics over explicit arena-resident frames and task control blocks.

Invocation path

route invocation
  → select Unit instance
  → copy payload into its arena
  → reset root TCB
  → call method entry
  → scan and dispatch ready continuations
  → poll host I/O when no task is ready
  → complete, suspend, yield, or terminate

The root TCB and persistent arena belong to the Unit instance. Continuation frames allocated after the recorded frame-region boundary belong to the current invocation and are released on ordinary completion.

Continuations

A continuation is identified by a compiled function ID and an arena-relative frame offset. The frame stores:

  • its caller continuation;
  • a packed program counter;
  • a result tag and result value;
  • its parent continuation;
  • a call-link state used during stack reconstruction and completion.

Function IDs are dense within one build. They are not portable symbols and cannot be assumed stable after redeploy.

See ABI for the exact frame layout.

Task tree

Every invocation starts with a root task control block. Spawned tasks become children in an arena-resident tree:

root TCB
├─ child TCB
│  └─ grandchild TCB
└─ child TCB

The tree carries completion, cancellation, detach, frame, and waiter state. The trampoline scans it root-first in depth-first order, skips cancelled subtrees, and dispatches ready work.

A TCB offset can be reused after deallocation. Debug identity therefore pairs the offset with its debug_stamp; the offset alone is vulnerable to an ABA mistake.

Ready work

The scheduler distinguishes several queues:

  • ready resume nodes continue a suspended frame with a tagged result;
  • ready loop nodes re-enter loop or yield continuations;
  • awaiter chains wake tasks waiting on child completion or selection;
  • stream control blocks coordinate consumer and producer waiters.

Nodes live in the same arena as the frames they reference, so relocation preserves their relationships. The host keeps only typed offsets and rebuilds absolute addresses from the current arena base.

Trampoline

The host trampoline repeatedly:

  1. activates the Unit instance’s link group and arena;
  2. asks generated scheduling code for the next ready continuation;
  3. resolves its build-local function ID through the group’s cached function table;
  4. calls the generated resume or loop function;
  5. services growth, collection, cancellation, debug, and preemption safepoints;
  6. polls exact I/O slots when no generated task is immediately ready.

There is no operating-system thread per Atoll task. Tasks interleave cooperatively on their Store reactor, while different Stores can run in parallel.

Suspension

A suspendable host call creates an I/O slot associated with the Unit instance and records a resume target. If the operation is pending, generated code returns to the trampoline. The Store reactor later polls the future.

Completion creates a ready-resume node containing:

(tcb, resume_function, frame)

The next scheduler pass dispatches that continuation with the operation’s result tag and value. Exact-slot wakers notify only the relevant operation; the runtime does not spawn one Tokio task for every I/O call.

See Host I/O for buffer and resource lifetimes.

Streams

An arena stream control block holds queue metadata plus consumer and producer awaiter chains. Handles use the low bit to distinguish an aligned task handle from a stream handle.

Backpressure is represented in the task graph: a consumer suspends when no item is available, and a producer can suspend when capacity is exhausted. Closing a stream records closure and wakes waiters through scheduler nodes.

Cancellation

Cancellation is hierarchical. Marking a TCB cancelled causes traversal to skip that task’s subtree, and pending operations associated with cancelled work are dropped or reaped according to their host contract.

Cancellation returns the CANCELLED result tag at a generated boundary. It does not roll back arbitrary external effects that completed before the cancellation was observed.

Termination is stronger than cancellation. A trap, forced stop, or interrupted ownership update can make the instance untrustworthy. The runtime poisons that instance and evicts its arena instead of attempting normal continuation.

Completion

The root task’s completion determines the invocation result. Detached tasks are not allowed to keep the caller waiting forever.

After the root completes, the trampoline drains work that is already ready for detached tasks, with a current bound of 4,096 steps. It does not wait for new detached I/O after root completion. Long-lived background responsibility should belong to a Unit or explicit runtime service, not an invocation-scoped detached task.

Preemption

Preemption is cooperative. Wasmtime epoch ticks and generated yield flags cause execution to return to a scheduler boundary so another invocation can make progress. Preemption preserves the Unit instance and continuation state.

Termination uses a separate control path and can poison the instance. Code and operators must not treat “yielded” and “terminated” as equivalent events.

Debug stops

Debug-instrumented code adds source safepoints. An armed breakpoint or step can suspend the invocation’s coroutine, capture its task and continuation stack, and shelve it in the Store. The reactor remains able to run unrelated instances, but the stopped Unit instance stays busy and cannot be reused.

See Debugger for stepping and concurrency rules.

Result tags

The frozen result-tag values are:

Tag Meaning
0 OK
1 ERR
2 CANCELLED
3 TIMEOUT
4 ERR_FLAT

The associated value lane is interpreted by the called operation and generated type metadata.

Invariants

  • generated code mutates one Unit instance on one Store reactor;
  • every suspended continuation has a live frame and TCB root;
  • all scheduler links are arena-relative offsets;
  • cancelled subtrees are not dispatched;
  • root completion bounds post-root detached work;
  • cooperative yield preserves state, while forced termination may poison it;
  • an invocation result does not imply rollback of completed external effects.
Navigation

Type to search…

↑↓ navigate↵ selectEsc close