Execution Architecture¶
This page describes how the current implementation creates a runtime, starts a guest process, and moves execution between workers and kernel WebAssembly.
Runtime Creation¶
Runtime.create receives kernel WebAssembly bytes and initializes a runtime
instance. The current implementation precompiles the module, allocates a
SharedArrayBuffer-backed page cache, creates a kernel worker, and sends an
init-kernel request.
sequenceDiagram
participant App as Application
participant Runtime as Runtime.create
participant KernelWorker as kernel worker
participant KernelWasm as kernel wasm exports
App->>Runtime: create({ wasmBytes, ramSize, networkBridge })
Runtime->>Runtime: precompile WebAssembly module
Runtime->>Runtime: allocate SharedArrayBuffer page cache
Runtime->>KernelWorker: init-kernel(wasmModule, sabPageCache)
KernelWorker->>KernelWasm: instantiate kernel environment
KernelWasm-->>KernelWorker: initial KernelRuntimeState
KernelWorker-->>Runtime: ready(kernelState)
Runtime-->>App: Runtime instance
The runtime owns the JavaScript/TypeScript worker lifecycle. The kernel owns guest-visible behavior and supervisor decisions; TypeScript executes the host effects needed to realize those decisions.
Kernel Supervisor ABI And Status Codes¶
The kernel exports status codes, syscall numbers, constants, and process/thread entry points through its WebAssembly ABI. The runtime reads those exports rather than maintaining an independent copy of the same contract.
The current ABI includes status categories for filesystem work, futex waits, pipe waits, epoll waits, vfork waits, exec-style process creation, clone-style thread or process creation, sleep, sockets, and JIT readiness. A status remains the low-level point where a thread step returns to TypeScript; it is not a grant of Linux policy authority to the runtime.
The versioned supervisor ABI adds structured thread events, host operations, host completions, resume records, decision records, debug snapshots, and deterministic log metadata. The control loop is:
sequenceDiagram
participant Thread as thread worker
participant Executor as TypeScript host executor
participant Supervisor as kernel supervisor
participant Host as browser / Node host
Thread->>Executor: status and synchronization data
Executor->>Supervisor: ThreadEvent
Supervisor-->>Executor: HostOp or selected ResumeThread
Executor->>Host: worker, memory, I/O, network, or timer effect
Host-->>Executor: result
Executor->>Supervisor: HostCompletion
Supervisor-->>Executor: updated decision or next operation
Executor->>Thread: resume only when selected
The ABI is additive so a responsibility can move behind an explicit record or decision export without copying constants or policy into TypeScript.
Process Startup¶
The SDK and runtime expose different levels of process startup.
- The SDK accepts a command name, resolves it against a guest
PATH, handles simple shebang fallback through/bin/sh, reads executable bytes, and calls the runtime. - The runtime accepts executable bytes and lower-level process options.
- The worker layer prepares memory, filesystem state, process identity, stdio, and thread-worker execution.
sequenceDiagram
participant App as Application
participant SDK as Tidemark SDK
participant Runtime as Runtime
participant KRPC as kernel-worker RPC
participant Owner as process owner host executor
participant Thread as thread worker
participant Supervisor as kernel wasm / supervisor
App->>SDK: run(command, args)
SDK->>Runtime: stat/read filesystem paths
Runtime->>KRPC: stat/read-file requests
KRPC-->>Runtime: executable bytes
SDK->>Runtime: spawn(executableBytes, argv, env, cwd)
Runtime->>Owner: create process handle
Owner->>KRPC: register process / resolve cwd / host lifecycle init
Owner->>Thread: prepare/init memory and kernel state
Thread->>Supervisor: execute with budget
Supervisor-->>Thread: status, exit, syscall, or blocking state
Thread-->>Owner: ThreadWorkerStatusMessage
Owner->>Supervisor: ThreadEvent
Supervisor-->>Owner: HostOp or resume decision
Owner->>Supervisor: HostCompletion after host effect
Owner-->>Runtime: stdout/exit/error events
Runtime-->>SDK: process result
SDK-->>App: exit code and output
This sequence is intentionally more explicit than a single run call. The
runtime has to coordinate browser workers, kernel state, guest memory,
filesystem state, and host I/O.
Worker Topology¶
flowchart TB
Runtime["Runtime instance"]
KernelWorker["kernel worker<br/>canonical runtime-facing state"]
Owner["process owner worker<br/>host executor and state transport"]
Pool["worker pool"]
ThreadA["thread worker"]
ThreadB["thread worker"]
Host["host bridges<br/>stdio, network, filesystem RPC"]
Supervisor["kernel supervisor<br/>Linux-shaped decision authority"]
Runtime --> KernelWorker
Runtime --> Owner
Runtime --> Host
Owner --> Pool
Pool --> ThreadA
Pool --> ThreadB
Owner <--> KernelWorker
ThreadA <--> Owner
ThreadB <--> Owner
Owner <--> Host
Owner <--> Supervisor
ThreadA --> Supervisor
ThreadB --> Supervisor
The runtime implementation reflects this topology through separate roles for kernel-worker state, process host execution, thread execution, host I/O, and shared-state transport. Runtime queues may track workers that are running, parked, or ready for a host action, but runnable-thread authority belongs to the supervisor.
Thread Workers¶
Thread workers are the runtime substrate for guest thread execution. A thread-worker executes a single guest thread against shared process memory and returns explicit status and synchronization data to the process owner. The runtime submits the relevant event to the supervisor, executes requested host effects, reports completion, and delivers supervisor-selected resumes without making the kernel depend on browser worker APIs.
flowchart TB
ProcessOwner["process owner host executor"]
SharedMemory["shared process memory<br/>WebAssembly.Memory / SharedArrayBuffer-backed state"]
ThreadA["thread worker A<br/>guest thread step loop"]
ThreadB["thread worker B<br/>guest thread step loop"]
KernelExports["kernel wasm exports<br/>supervisor"]
Status["status + sync transport"]
Decision["HostOp / ResumeThread"]
ProcessOwner --> ThreadA
ProcessOwner --> ThreadB
ThreadA <--> SharedMemory
ThreadB <--> SharedMemory
ThreadA --> KernelExports
ThreadB --> KernelExports
KernelExports --> Status
Status --> ProcessOwner
ProcessOwner --> KernelExports
KernelExports --> Decision
Decision --> ProcessOwner
This design supports workloads that expect a threaded Linux userland substrate: language runtimes, compiler drivers, build tools, thread pools, futex waits, signal interruption, and child process orchestration. Those workloads exercise the substrate; they are not special cases in the runtime architecture.
Step And Status Loop¶
Thread workers receive prepare, init, and step messages. A step includes a
budget and the kernel state required to continue. The thread worker returns
status messages that can include register details, syscall number, kernel
state, fd/OFD snapshots, pipe slots, socket snapshots, guest memory writes,
kernel memory writes, sync effects, child-exit records, and blocking hints.
stateDiagram-v2
[*] --> Prepared
Prepared --> Ready: init
Ready --> Running: step(budget)
Running --> Reported: status / ThreadEvent
Reported --> HostEffect: supervisor HostOp
HostEffect --> Reported: HostCompletion
Reported --> Ready: supervisor selects continuation
Reported --> Blocked: supervisor records blocked state
Blocked --> Ready: supervisor selects resume
Running --> Exited: exit status
Running --> Failed: error
Exited --> [*]
Failed --> [*]
The runtime receives enough structured state to transport the event and perform the selected host effect. The supervisor decides whether execution continues, a blocked syscall resumes, child state becomes visible, or lifecycle cleanup is required.
Fork, Vfork, And Execve¶
Fork-style operations are not only memory copies. They also involve fd/OFD ownership, pipe state, process identity, child-exit records, cwd and executable state, and worker readiness ordering.
The current implementation exposes this as an explicit supervisor and host handoff protocol:
- kernel exports describe spawn kind and pending handoff state,
- supervisor decisions define lifecycle and parent-visible ordering,
- runtime worker modules execute requested memory and worker operations,
- host completions return success or failure to the supervisor,
- tests cover vfork/execve success, failure, parent restoration, and fd/OFD isolation cases.
flowchart LR
Parent["parent process host executor"]
Status["STATUS_VFORK_WAIT<br/>STATUS_EXECVE_SPAWN<br/>STATUS_CLONE_SPAWN"]
Supervisor["kernel supervisor<br/>lifecycle decision"]
HostOp["worker / memory HostOp"]
KernelWorker["kernel worker host effect"]
Child["child process owner"]
Thread["thread worker init"]
Parent --> Status
Status --> Supervisor
Supervisor --> HostOp
HostOp --> KernelWorker
HostOp --> Child
Child --> Thread
KernelWorker --> Supervisor
Child --> Supervisor
The handoff protocol has to cover parent suspension and supervisor-selected resume, child creation, fd/OFD and pipe visibility, child-exit publication, and failure rollback. Tests should cover the kernel decision and the retained host effect separately before using a workload as composition evidence.