lukewagner opened issue #14117:
There are two cases where Wasmtime diverges from what's currently in the CM spec repo when non-
async-typed functions are involved. Filing together b/c maybe they tickle some of the same code bits:In the first case, captured in test/async/no-sibling-resume-during-sync-call.wast (currently in a branch): while a synchronous function is running, the scheduler isn't supposed to switch to threads in other component instances. (Doing so would allow surprise-reentrance during a sync call, which the above WAST actually exhibits.) This WAST tests hits this case first using only 0.3.0 features (in
$Tester1) and then using cooperative threads (in$Tester2).In the second case, captured in test/async/sync-call-async-with-ready-thread.wast (also currently in a branch): the spec currently says that if you synchronously call an
async-typed function, whether it traps or not does not depend on the current thread's task's function type (since you can easily switch between threads of different tasks while executing a synchronous call, which is what the above WAST does). Instead, what matters is: if you block (for any reason, not just sync-calling anasyncimport) during a synchronous call before returning a value: if there are no other threads ready to run in the same instance, you trap. Currently, Wasmtime has an eager trap based on the current thread's task's function type, but if you switch to another thread (which is part of anasynctask) you get the spec-defined trap-if-cant-switch behavior. This is shown in the WAST using only 0.3.0 features (in$Tester1) and then using cooperative threads (in$Tester2).
lukewagner added the bug label to Issue #14117.
dicej assigned dicej to issue #14117.
dicej commented on issue #14117:
the spec currently says that if you synchronously call an
async-typed function, whether it traps or not does _not_ depend on the current thread's task's function type (since you can easily switch between threads of different tasks while executing a synchronous call, which is what the above WAST does). Instead, what matters is: if you block (for any reason, not just sync-calling anasyncimport) during a synchronous call before returning a value: if there are no other threads ready to run in the same instance, you trap.Can you clarify what "during a synchronous call before returning a value" means here? Is the "synchronous" part referring to how the current thread's task was called e.g. via a synchronously-lowered import? I.e. is this only about how the function was lowered and not about the type?
lukewagner commented on issue #14117:
Oh sorry, I meant "during a call to a non-
async-typed function".
dicej commented on issue #14117:
In that case, how does that relate to the "does not depend on the current thread's task's function type" part earlier? Isn't "the current thread's task's function type" another way of saying "during a call to a [whatever]-typed function"? Are we talking about the type of the function that was called when the current thread's task was created or the type of a function that is being called _by_ the current thread's task? And if it's the latter, what if we're blocking on something that's not a function, e.g. an intrinsic like
subtask.cancel?
lukewagner commented on issue #14117:
We followed up offline, but just for the thread: what matters and is a bit subtle is the function type of the dynamic call context, which stays the same even when a thread contained by a sync task switches to a thread contained by an async task.
Just as an update on the tests: I expanded and split the above-linked 2 tests into 3 tests and then merged them to main in CM/#691; see the 3
test/async/during-sync-call-*files intest/nyi.txtfor the list. In particular, the original tests above depend on another divergent Wasmtime behavior (being able to switch to anasync callbacktask's thread during a sync call, but only in component-to-component calls, host-to-component calls correctly prevent), which I'll write up separately.
Last updated: Aug 30 2026 at 09:07 UTC