WASI & syscalls
Compiled binaries from clang, and any wasm32-wasi module you bring,
run on the Nimbus wasi_snapshot_preview1 host. All 46 preview1
functions work.
Preview1 itself has no sock_open, bind or listen. It can only act on
descriptors the host already handed over. Nimbus hands them over through
synthetic paths. path_open('/dev/nimbus/listen/<port>') binds a listening
descriptor. A guest compiled against wasi-libc takes a connection from it
with sock_accept; a guest layered over its own filesystem (ruby.wasm)
reads the descriptor instead. Both end at the same socket fd, so a WASM
server takes /port traffic the same way a Node one does.
Blocking I/O uses JSPI. Socket calls, poll_oneoff and the file reads
that can reach the session filesystem are wrapped in
WebAssembly.Suspending. Every entry into such a guest runs under
WebAssembly.promising. V8 requires the suspender at call time even for
an import that returns a plain errno, so there is no partial adoption and
no fallback. A guest whose entries are synchronous by contract asks for
unwrapped imports instead. The terminal render backend is one, driven per
frame from a sync caller. Such a guest cannot be given anything that
blocks.
Outbound TCP uses path_open('/dev/tcp/<host>/<port>') to open a real
cloudflare:sockets connection. poll_oneoff can mix fd, clock, and
socket subscriptions.
A suspension lasts only as long as the request that started it. A workerd
request context resumes only the wasm stacks it suspended itself, so a
program parked in accept stays parked when the next request arrives.
Servers on the virtual-socket kernel run the other way round. The kernel
queues the connection and asks the runtime to service it on one dedicated
cooperative pump, the only place a JSPI suspension is legal. Pyodide and
ruby.wasm serve loopback ports this way.
JSPI suspends a call, but it cannot snapshot a stack. Programs that need
fork or setjmp, bash among them, are additionally instrumented with
Asyncify. Asyncify can unwind a running program’s call stack to memory and
rewind it in another instance. The process
fabric covers what that unlocked.
O_NOFOLLOW and O_APPEND work, symlinks survive path_rename, and
read(2) on a socket fd goes to the socket. wasi-libc maps read to
fd_read for every fd, so the host has to route it correctly.
Programs see NIMBUS_ABI=wasm32-wasi-nimbus. The in-session clang emits
it, and the runtime catalog uses it to classify artifacts. WASM magic or
a saved exec bit sends ./prog through the WASI runner with a pid and a
process tab.
workerd blocks request-time WASM compilation from raw bytes. Modules must arrive pre-compiled in the module map. Pyodide extension packages must therefore be declared startup modules, while arbitrary dynamic loading fails with a clear diagnostic.
WASI files are a cache over the session filesystem. The spawn seed is a manifest of sizes. Content is fetched on first read, and writes go back as they happen, so a process that never exits still persists. bash and python are the two runtimes not yet on it. Each still carries a private filesystem that copies the subtree in and reports a diff on exit.
stdin is EOF, and there are no inbound sockets. The remaining gaps are tracked with designs.
Threads
Section titled “Threads”wasi-threads asks the host to instantiate a second copy of the same
module against the same shared linear memory and start
wasi_thread_start in it. Worker Loader isolates each own their
WebAssembly.Memory, SharedArrayBuffer stays within one isolate, and
Atomics.wait on isolate-local memory has nothing to wait on. A thread
is defined by the memory it shares, so an isolate backs a process.
thread_spawn is therefore left out of the import table. A program
that links pthreads stops at wasm-ld with undefined symbol: thread_spawn rather than running with wrong memory semantics.
Parallelism lives one level up, at the process boundary: a facet per
process. That facet gets its own memory budget when it runs on a peer
DO.
The design note
lists what the Workers runtime would have to expose for in-language
threading to work.