When true, use a MessageChannel-based poller to check all channels instead of per-channel Atomics.waitAsync listeners.
This avoids a V8 bug where Atomics.waitAsync microtask chains from multiple concurrent processes freeze the main thread. The poller uses MessageChannel for ~0ms dispatch (bypassing the browser's 4ms timer clamp on setTimeout/setInterval), with periodic setTimeout yields every 4ms to keep timers and rendering alive.
Enable this in browser environments where the kernel runs on the main thread. In Node.js (where setImmediate is native), the default event-driven mode (Atomics.waitAsync) is preferred.
Live /dev/fb0 mappings reported by the kernel, indexed by pid.
Renderers (canvas in browser, no-op in Node) read from this on
each frame; the kernel populates it via the host_bind_framebuffer
import.
Add a new channel (e.g. for a thread) to an existing process registration.
Uses the process's existing memory. If tid is provided, tracks the mapping
so handleExit can identify thread exits. threadFnPtr / threadArgPtr
are stored when the thread was created via clone() so handleFork can
route a fork() from this thread back through its entry point.
Optionaltid: numberOptionalthreadFnPtr: numberOptionalthreadArgPtr: numberAllocate a fresh pid for a top-level spawn from a host. Skips any pids already in the kernel's process table (forked children, the virtual init at pid 1, etc.). The host is no longer expected to pick pids; this is the single source of truth.
Append data to a process's stdin buffer without marking stdin as a pipe. Used for interactive stdin where data arrives incrementally. Wakes any blocked stdin readers after appending.
Channel count the program last configured on /dev/dsp.
Bytes buffered in the /dev/dsp ring waiting to be drained.
Sample rate (Hz) the program last configured on /dev/dsp.
Drain up to out.byteLength bytes of PCM audio buffered in
/dev/dsp into out. Returns the number of bytes copied, always
a multiple of the active frame size (2 bytes mono / 4 bytes
stereo).
The host typically drives this from an AudioWorkletNode or
AudioBufferSourceNode scheduler that pulls samples at the rate
an AudioContext reports. The kernel ring drops oldest frames on
overflow rather than blocking, so falling behind a few RAFs costs
audio but never wedges DOOM.
Dump syscall profiling data to stderr. Call from your serve script: process.on('SIGINT', () => { kernelWorker.dumpProfile(); process.exit(); });
Only produces output when WASM_POSIX_PROFILE=1 env var is set.
Per-process fork counter (parent side, incremented inside
kernel_fork_process on success). Used by the spawn regression tests
to assert that a SYS_SPAWN call did NOT fall back to the fork path.
Returns u64::MAX (as bigint) if the pid does not exist; callers
should compare against an explicit before-value rather than treating
"no process" as "0 forks".
Get the underlying kernel instance for direct access.
ABI version the kernel advertised at startup via its
__abi_version export. Worker processes compare against this
and refuse to run programs built against an incompatible ABI.
Get the kernel Wasm instance.
Return the wasm Memory for pid (or undefined if no such
process is registered). Renderers use this to build typed-array
views over the bound framebuffer region.
Initialize the kernel. Loads kernel Wasm and validates the host adapter ABI.
Push a mouse event into the kernel's /dev/input/mice queue. The
kernel buffers a 3-byte PS/2 frame; any process blocked in
read() or poll() on the device is woken on the next retry tick.
Run kernel-side exec setup: close CLOEXEC fds, reset signal handlers. Returns 0 on success, negative errno on failure. Called by onExec callbacks after confirming the target program exists.
Notify the kernel that a host worker for pid died asynchronously
(uncaught wasm trap, instantiation failure, externally terminated
Worker) WITHOUT going through the normal SYS_EXIT_GROUP path.
Without this, an OOB/instantiation crash leaves the kernel
believing the process is still alive: any concurrent waitpid in
the parent then blocks until host destroy. P-06 / K-03 exposed
this — the child's wasm trapped during _start, the worker
reported it via {type:"error"}, the host posted stderr +
deactivated the process locally, but the kernel never marked the
pid as a zombie or woke the parent.
Marks the process as signal-terminated in Rust using signum (default
SIGSEGV = 11), queues SIGCHLD on the parent, and wakes any parked
waitpid / waitid.
Idempotent via hostReaped: if the kernel already saw a clean
SYS_EXIT for this pid, this is a no-op (the kernel's exit
status wins). Host-side cleanup (channel removal, timer
cancellation) is still the caller's responsibility — call
deactivateProcess after this if the pid is going away.
Public wake helper for host-side pipe writes (TCP bridges, HTTP
bridges, etc.). Call this AFTER directly writing into a pipe via
kernel_pipe_write or kernel_inject_connection.
In order:
pendingPipeReaders).pipeIndices includes this pipe (pendingPollRetries).
Pass pidFilter to restrict the wake to a single owning
pid — used by the Node TCP bridge when dispatching an
inbound connection to a specific listener.scheduleWakeBlockedRetries) for
everything else.Without step 2, blocked pollers wait for the fallback timer in
handleBlockingRetry to fire, which is the bug behind PR fixing
the WordPress LAMP demo's slow install.php (see commit history).
OptionalpidFilter: numberPublic wake helper for host-side pipe reads (response pump in the TCP/HTTP bridges). Call this AFTER directly reading data from a pipe so any process blocked writing because the pipe was full can resume, plus a broad wake.
Notify the kernel that a thread has exited. Removes thread state from the process's thread table.
Register a callback for PTY output data.
Pick the next listener target for a port via round-robin. Only considers processes that are still registered.
Public so external callers (the in-kernel HTTP request bridge) can resolve a port to a {pid, fd} before injecting a connection.
Remove old channel/registration state for a process about to exec. Does NOT remove from kernel process table (exec keeps the same pid). Does NOT cancel timers (POSIX: timers are preserved across exec).
Read all available data from a PTY master (slave output → host). Returns data or null if empty.
Write data to a PTY master (host → line discipline → slave). Wakes any process blocked on reading the slave side.
Resize a PTY and send SIGWINCH to the foreground process group.
Read /proc/[pid]/maps for a foreign process. Returns the raw Linux-
style text (one line per mapped region) or null if the pid doesn't
exist. Empty string if the process has no mappings.
Register a process and its thread channels with the kernel. Each channel is a region in the process's shared Memory.
Optionaloptions: RegisterProcessOptionsRemove a channel from a process registration (e.g. when a thread exits).
Remove a process from the kernel's PROCESS_TABLE. Called when a zombie is reaped by wait/waitpid.
Remove a pid from the wasm kernel's ProcessTable entirely. Used by the worker-entry's crash path: when a worker dies via a wasm trap (signature mismatch, OOM, etc.) the kernel never saw a SYS_EXIT, so its ProcessTable still has the pid in state=Running. After this runs, kernel_enum_procs no longer reports it and a parent's waitpid() returns ECHILD — accurate for "the process really is gone."
Don't call this for normal exits — the kernel marks those Exited (zombie) so the parent can still reap.
Send an HTTP/1.1 request to a server running inside the kernel and
resolve with the parsed response. Bypasses real TCP — uses
kernel_inject_connection + kernel_pipe_* directly.
Used by both the browser service-worker bridge and the Node host's
fetchInKernel API (see
docs/plans/2026-04-30-external-kernel-http-request-interface.md).
Set the program's initial brk. Compact process layouts pass the first
guest-managed byte after the host control slab; legacy callers may pass
the program's __heap_base directly. Must run before the new process
worker can issue its first syscall.
Accepts bigint (preferred — what extractHeapBase returns) or
number. The kernel export takes a usize, whose JS representation
depends on the kernel wasm pointer width.
Set the program-break ceiling for a process. Hosts use this to reserve low in-memory control pages for syscall channels and pthread TLS without letting brk grow into them.
Set a freshly-created process's initial real/effective uid and gid. Must be called after registerProcess and before the process starts.
Set the working directory for a process. Must be called after registerProcess and before the process starts.
Set the mmap address space ceiling for a process. Must be called before the process worker starts to prevent mmap from allocating in the thread channel/TLS region.
Set the automatic mmap lower bound for a process. Compact process layouts set this to the first guest-managed byte after the host control prefix.
Set the next child PID to allocate.
Set stdout/stderr capture callbacks on the underlying kernel instance. Must be called after construction but works at any time.
Provide data that will be returned when the process reads from stdin (fd 0). Data is returned in chunks until exhausted, then EOF is returned. Must be called before the process starts reading stdin.
Create a PTY pair and wire fds 0/1/2 of pid to the slave side.
Returns the PTY index, or throws on failure.
Unregister a process. Stops listening on its channels and removes it from the kernel's process table.
How many syscalls to process via microtask before yielding to the event loop via setImmediate. Default 64 is optimal for Node.js. Set to 1 in browser environments where the kernel runs on the main thread.