Skip to content

Add wasm32-wasip2 backend using wasi:clocks#85

Open
cargopete wants to merge 1 commit into
async-rs:masterfrom
cargopete:wasip2-backend
Open

Add wasm32-wasip2 backend using wasi:clocks#85
cargopete wants to merge 1 commit into
async-rs:masterfrom
cargopete:wasip2-backend

Conversation

@cargopete
Copy link
Copy Markdown

Summary

Adds a wasm32-wasip2 backend for Delay, backed by wasi:clocks/monotonic-clock and driven by the wstd reactor.

Motivation

On wasm32-wasip2 there is no wasm-bindgen, so futures-timer falls into the native backend — which spawns a background timer-wheel thread. The WASI Preview 2 component model is single-threaded, so that thread never runs and the first poll of any Delay aborts at runtime:

thread 'main' panicked at futures-timer-3.0.4/src/native/delay.rs:126:
timer has gone away

This makes futures-timer unusable on wasm32-wasip2 today, which in turn breaks every downstream library that relies on it (e.g. several rust-libp2p behaviours: ping, kad, gossipsub, request-response, rendezvous, and the Swarm idle-connection timeout). Because [patch.crates-io] only applies in the final binary's workspace, downstream libraries cannot fix this for their own users — it has to be fixed here.

What this does

Adds a third backend selected via target_env = "p2" (so wasm32-wasip1 and any future preview stay on native):

target backend
wasm32-wasip2 newwasi:clocks + wstd reactor
wasm32 + wasm-bindgen (non-wasip2) wasm (setTimeout via gloo-timers)
everything else native (thread-based timer wheel)

The new Delay matches the existing API exactly: new(dur), reset(&mut self, dur), impl Future<Output = ()>, impl Debug.

The wstd / wasip2 dependencies are gated to cfg(all(target_arch = "wasm32", target_os = "wasi", target_env = "p2")), so they are pulled in only for the target where the existing backend is already broken — there is no dependency or behavioural change for any currently-working target.

Why this is low-risk

The native backend already panics at runtime on wasm32-wasip2, so this is a pure fix: no working configuration changes. native (host) and wasm32-wasip1 (stays on native) are unaffected, and the wasm-bindgen browser path is unchanged.

Testing

  • Builds cleanly for wasm32-wasip2 (new backend), wasm32-wasip1 (falls through to native, no wstd pulled in), and the host target (unchanged).
  • Verified end-to-end against rust-libp2p: a libp2p-ping Swarm running as a wasm32-wasip2 component completes a full ping round-trip (real RTT, no panic) when futures-timer is patched to this branch.

Note for reviewers

wstd is the de-facto async reactor for wasm32-wasip2; the backend awaits the wasi:clocks pollable through it. A fully reactor-agnostic implementation isn't possible because WASI 0.2 has no ambient reactor — each runtime supplies its own. If a target-gated wstd dependency is unwelcome, I'm happy to move the backend behind an opt-in wasip2 feature instead of auto-selecting it. Let me know which you'd prefer.

The thread-based native backend cannot run on wasm32-wasip2 (the WASI
component model is single-threaded), so polling a Delay there aborts with
"timer has gone away". Add a target-gated backend that arms a
wasi:clocks/monotonic-clock timer and awaits it through the wstd reactor.

Selected via target_env = "p2" so wasip1 and future previews keep the
native backend. The wstd/wasip2 dependencies are pulled in only for
wasm32-wasip2, where the native backend is already broken at runtime, so
there is no regression for existing targets.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant