An async-lifted export (wit-bindgen callback ABI) that parks on a guest-internal Waker — nothing host-side outstanding, woken later by a different export call — traps at the sync drive entry:
Trap: wasm trap: deadlock detected: event loop cannot make further progress
(export 'next': no thread is ready and no host call is outstanding)
This is the long-poll shape (next: async func() -> event woken by a later push). Under wasmtime call_concurrent/run_concurrent the export's future stays pending until the second call readies the task; the embedder is still able to act, so it is not a deadlock in the spec's sense — the guest task is WAITing on its wit-bindgen inter-task-wakeup stream, whose writer is guest code reachable through another export.
Minimal repro (wit-bindgen 0.60, async-spawn + inter-task-wakeup, jspi: false, runtime at 80ee6cb):
world guest {
import note: func(what: string);
export next: async func() -> u32; // parks on a thread_local Waker until push()
export push: async func(v: u32); // pushes a value, wakes the waiter
}
const p = inst.exports.next(); // traps here (drive: deadlock)
await inst.exports.push(7); // never reached
Guest: next is poll_fn(|cx| { pop queue or store cx.waker(); Pending }).await; push pushes and wake()s.
Expected: next() returns a pending Promise; push(7) resolves it with 7. Observed: trap on the next() call.
Context: found building polyvisor's kernel event path (a events.next long-poll export). Worked around by making the export non-parking and draining from the glue after each dispatched export call; recorded in polyvisor's design record as a polyengine divergence to revisit. Sibling of #289 (that one was a parked driver missing a host call registration; this one is "no host call at all is not a deadlock while the embedder holds exports").
An async-lifted export (wit-bindgen callback ABI) that parks on a guest-internal
Waker— nothing host-side outstanding, woken later by a different export call — traps at the syncdriveentry:This is the long-poll shape (
next: async func() -> eventwoken by a laterpush). Under wasmtimecall_concurrent/run_concurrentthe export's future stays pending until the second call readies the task; the embedder is still able to act, so it is not a deadlock in the spec's sense — the guest task is WAITing on its wit-bindgen inter-task-wakeup stream, whose writer is guest code reachable through another export.Minimal repro (wit-bindgen 0.60,
async-spawn+inter-task-wakeup,jspi: false, runtime at 80ee6cb):Guest:
nextispoll_fn(|cx| { pop queue or store cx.waker(); Pending }).await;pushpushes andwake()s.Expected:
next()returns a pending Promise;push(7)resolves it with 7. Observed: trap on thenext()call.Context: found building polyvisor's kernel event path (a
events.nextlong-poll export). Worked around by making the export non-parking and draining from the glue after each dispatched export call; recorded in polyvisor's design record as a polyengine divergence to revisit. Sibling of #289 (that one was a parked driver missing a host call registration; this one is "no host call at all is not a deadlock while the embedder holds exports").