Skip to main content

Module vm

Module vm 

Source
Expand description

Single-owner VM event loop.

rquickjs’s schedular wake queue holds a SINGLE AtomicWaker slot, re-registered by whichever future last polled the schedular. Any short-lived async_with! that awaits inside its closure polls the schedular, steals that slot, and dies with it — after which every external completion of a schedular task (a backend response resolving an awaited page.evaluate, an mpsc send into a ctx.spawn pump) wakes a dead task and the VM never resumes. AsyncRuntime::drive() is no fix: it contends for the same single slot, is only woken by new spawns (never by wakes of existing tasks), and crashes under multi-thread load (SIGSEGV in its lock-release path).

The fix is the architecture every production QuickJS embedding converges on (LLRT, txiki.js, quickjs-libc, Deno’s isolate loop): exactly ONE never-completing future owns the VM and its schedular; everything else sends messages. spawn_vm_loop starts that future (a single persistent async_with per session VM); VmHandle::with submits a closure as a job which the loop ctx.spawns onto the schedular, so jobs run concurrently with each other and with the loop’s own recv — an execute parked on a host await never blocks a route/exposeFunction/WS dispatch job arriving behind it. Because the loop future never completes, every wake — schedular queue slot, spawner listen, channel recv — always targets a live task.

Structs§

VmHandle
Cloneable submission handle to a session’s VM event loop.
VmShutdown
Signals the VM event loop to finish. Dropping it (with the session) makes the loop break out of recv, so the loop future completes normally and releases its AsyncContext on its own task — never abort the loop task: tearing the WithFuture down mid-flight on a foreign thread leaves live GC objects behind and trips QuickJS’s JS_FreeRuntime gc_obj_list assertion.

Functions§

spawn_vm_loop
Spawn the session’s single persistent VM driver. The loop runs until the returned VmShutdown is dropped (or every VmHandle clone is gone); until then the task holds a clone of ctx (keeping the runtime alive) and is the only future that ever polls the runtime’s schedular.

Type Aliases§

VmJob
A unit of work executed inside the session’s VM event loop. The closure runs under the runtime lock on the loop’s execution context; its future is ctx.spawned so it interleaves with other jobs.