diff --git a/src/integration.mbt b/src/integration.mbt index 896cdf37..c7ff1ded 100644 --- a/src/integration.mbt +++ b/src/integration.mbt @@ -41,3 +41,27 @@ pub fn run_async_main(main : async () -> Unit) -> Unit { let _ = @coroutine.spawn(main) @event_loop.reschedule() } + +///| +/// Scheduler-only entry for wasm / wasm-gc. The async library does not +/// provide IO on these targets (`sleep`, `Timer`, sockets, fs, etc. all +/// `abort` via the existing `unimplemented.mbt` stubs), but pure +/// coroutine code (`pause`, `with_task_group`, `aqueue`, `semaphore`, +/// `cond_var`) does not depend on the event loop and works fine — this +/// shim just drains the ready queue. +#coverage.skip +#cfg(target="wasm") +#doc(hidden) +pub fn run_async_main(main : async () -> Unit) -> Unit { + let _ = @coroutine.spawn(main) + @event_loop.reschedule() +} + +///| +#coverage.skip +#cfg(target="wasm-gc") +#doc(hidden) +pub fn run_async_main(main : async () -> Unit) -> Unit { + let _ = @coroutine.spawn(main) + @event_loop.reschedule() +} diff --git a/src/internal/event_loop/unimplemented.mbt b/src/internal/event_loop/unimplemented.mbt index d3f8c5c2..c5f4937c 100644 --- a/src/internal/event_loop/unimplemented.mbt +++ b/src/internal/event_loop/unimplemented.mbt @@ -38,3 +38,18 @@ pub fn Timer::cancel(timer : Timer) -> Unit { ignore(timer) abort("`Timer::cancel()` is unimplemented on WASM backend") } + +///| +/// WASM stub for the scheduler-only `reschedule` entry point. Drains +/// immediately-ready coroutines (including any wake-ups produced by +/// running coroutines themselves) and then returns. Gating on +/// `has_immediately_ready_task` rather than `no_more_work` ensures +/// blocked coroutines (`blocking > 0`, e.g. suspended on an external +/// host callback) do NOT cause this function to tight-spin: when there +/// is nothing ready to run we exit and yield back to the host, which +/// can re-enter via `run_async_main` once new work is available. +pub fn reschedule() -> Unit { + while @coroutine.has_immediately_ready_task() { + @coroutine.reschedule() + } +}