Skip to content

Conversation

@dicej
Copy link
Contributor

@dicej dicej commented Nov 18, 2025

This implements a spec change (PR pending) such that tasks created for calls to synchronous exports may not call potentially-blocking imports or return wait or poll callback codes prior to returning a value. Specifically, the following are prohibited in that scenario:

  • returning callback-code.{wait,poll}
  • sync calling an async import
  • sync calling subtask.cancel
  • sync calling {stream,future}.{read,write}
  • sync calling {stream,future}.cancel-{read,write}
  • calling waitable-set.{wait,poll}
  • calling thread.suspend

This breaks a number of tests, which will be addressed in follow-up commits:

  • The {tcp,udp}-socket.bind implementation in wasmtime-wasi is implemented using Linker::func_wrap_concurrent and thus assumed to be async, whereas the WIT interface says they're sync, leading to a type mismatch error at runtime. Alex and I have discussed this and have a general plan to address it. EDIT: addressed by Relax required host capabilities in wasip3 tcp/udp bindings #12085

  • A number of tests in the tests/component-model submodule that points to the spec repo are failing. Those will presumably be fixed as part of the upcoming spec PR (although some could be due to bugs in this implementation, in which case I'll fix them). EDIT: addressed by add async to funcs that need to block in WAST tests WebAssembly/component-model#577

  • A number of tests in tests/misc_testsuite are failing. I'll address those in a follow-up commit.

@dicej dicej requested a review from alexcrichton November 18, 2025 18:30
@dicej dicej force-pushed the trap-blocking-in-sync-tasks branch from c6c26c4 to 3547452 Compare November 18, 2025 18:33
@github-actions github-actions bot added the wasmtime:api Related to the API of the `wasmtime` crate itself label Nov 18, 2025
@alexcrichton
Copy link
Member

Talked about this with @dicej today, current blockers are:

  • Waiting on upstream PR to the spec to have an official point-of-reference
  • Current upstream tests are failing, and upstream spec PR likely to update.
  • Tests for "full matrix of trapping behavior" still needed

@dicej
Copy link
Contributor Author

dicej commented Nov 24, 2025

Regarding the {tcp,udp}-socket.bind test failures, I've opened WebAssembly/wasi-sockets#144.

Eventually, we'll want a proper way for host functions to "cheat" and block the whole guest without monopolizing the Store, as well, but no need to block this PR on that.

@alexcrichton
Copy link
Member

New thought: I think we're going to be required to implement "component-model-sync function can do async things on the host" in Wasmtime. Ignoring p3 for a moment, that's exactly how all async works in WASIp2. All WASIp2 functions are "sync" functions which leverage host superpowers to suspend the guest, and we can't break WASIp2, so I don't think that "just solve tcp/udp for wasip3" is a viable solution after all.

@dicej
Copy link
Contributor Author

dicej commented Nov 24, 2025

All WASIp2 functions are "sync" functions which leverage host superpowers to suspend the guest, and we can't break WASIp2

Agreed, but I don't see how that's relevant to this PR. Sync-typed exports are still permitted to call sync-typed imports, and wasmtime-wasi's p2 implementation uses Linker::func_wrap_async, which defines a sync-typed host function, so nothing in this PR or the proposed spec changes will break wasmtime-wasi's p2 implementation.

Certainly we'll need to confront p2 head-on once we remove or replace Linker::func_wrap_async, but we're not doing that here.

@alexcrichton
Copy link
Member

Er right, yes, wires crossed again. That means though that #12085 is possible which "fixes" tcp/udp.

@dicej dicej force-pushed the trap-blocking-in-sync-tasks branch from 3d14cbf to c3fb452 Compare November 24, 2025 23:04
@dicej
Copy link
Contributor Author

dicej commented Nov 25, 2025

Some of the WAST tests are hanging and/or busy looping. I'll investigate this morning.

dicej added a commit to WebAssembly/component-model that referenced this pull request Nov 25, 2025
This anticipates the forthcoming changes to WIT/CM async and helps us get CI
green for bytecodealliance/wasmtime#12043

Signed-off-by: Joel Dice <[email protected]>
@dicej dicej marked this pull request as ready for review November 25, 2025 17:06
@dicej dicej requested a review from a team as a code owner November 25, 2025 17:06
@dicej
Copy link
Contributor Author

dicej commented Nov 25, 2025

CI is green now; I'm temporarily pointing the tests/component-model submodule at WebAssembly/component-model#577 until that PR is merged.

@dicej
Copy link
Contributor Author

dicej commented Nov 25, 2025

I believe we're just waiting on a spec PR (hopefully accompanied by WAST tests covering the changes) at this point.

dicej added 9 commits December 1, 2025 15:05
This implements a spec change (PR pending) such that tasks created for calls to
synchronous exports may not call potentially-blocking imports or return `wait`
or `poll` callback codes prior to returning a value.  Specifically, the
following are prohibited in that scenario:

- returning callback-code.{wait,poll}
- sync calling an async import
- sync calling subtask.cancel
- sync calling {stream,future}.{read,write}
- sync calling {stream,future}.cancel-{read,write}
- calling waitable-set.{wait,poll}
- calling thread.suspend

This breaks a number of tests, which will be addressed in follow-up commits:

- The `{tcp,udp}-socket.bind` implementation in `wasmtime-wasi` is implemented
  using `Linker::func_wrap_concurrent` and thus assumed to be async, whereas the
  WIT interface says they're sync, leading to a type mismatch error at runtime.
  Alex and I have discussed this and have a general plan to address it.

- A number of tests in the tests/component-model submodule that points to the
  spec repo are failing.  Those will presumably be fixed as part of the upcoming
  spec PR (although some could be due to bugs in this implementation, in which
  case I'll fix them).

- A number of tests in tests/misc_testsuite are failing.  I'll address those in
  a follow-up commit.

Signed-off-by: Joel Dice <[email protected]>
`check_blocking` needs access to the current task, but that's not set for
post-return functions since those should not be calling _any_ imports at all, so
first check for that.

Signed-off-by: Joel Dice <[email protected]>
This amounts to adding `async` to any exported component functions that might
need to block.

Signed-off-by: Joel Dice <[email protected]>
Per the proposed spec changes, `thread.yield` should return control to the guest
immediately without allowing any other thread to run.  Similarly, when an
async-lifted export or callback returns `CALLBACK_CODE_YIELD`, we should call
the callback again immediately without allowing another thread to run.

Signed-off-by: Joel Dice <[email protected]>
Signed-off-by: Joel Dice <[email protected]>
Note that this temporarily updates the `tests/component-model` submodule to the
branch for WebAssembly/component-model#577 until that PR
is merged.

Signed-off-by: Joel Dice <[email protected]>
This clarifies that such a task cannot block prior to returning.

Signed-off-by: Joel Dice <[email protected]>
@dicej dicej force-pushed the trap-blocking-in-sync-tasks branch from 4408972 to 497ba53 Compare December 1, 2025 22:28
@pannous
Copy link

pannous commented Dec 2, 2025

the following are prohibited in that scenario:
> sync calling an async import

sorry again how is that not function coloring?

I somehow forgot to address this earlier.  Thanks to Luke for catching this.

Note that this commit doesn't include test coverage, but Luke's forthecoming
tests in the `component-model` repo will cover it, and we'll pull that in with
the next submodule update.

Signed-off-by: Joel Dice <[email protected]>
@dicej dicej requested a review from a team as a code owner December 2, 2025 14:58
@alexcrichton
Copy link
Member

@pannous if you have technical concerns about this change, mind bringing it up on WebAssembly/component-model#578? That'll be a better forum for discussing the design than here

@alexcrichton
Copy link
Member

@dicej did you have anything else you wanted to sort out with this or is it ready to go?

@dicej
Copy link
Contributor Author

dicej commented Dec 4, 2025

@dicej did you have anything else you wanted to sort out with this or is it ready to go?

Currently the tests/component-model submodule is pointing at my PR branch, and we can't point it to the main branch until WebAssembly/component-model#578 is merged. If we're ok with temporarily pointing at the PR branch, we can merge this; otherwise, we need to wait.

@alexcrichton
Copy link
Member

Could this ignore the upstream tests temporarily and/or vendor working copies of them?

Behavior-wise though there's nothing more you're looking to add here?

Copy link
Member

@alexcrichton alexcrichton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two extra thoughts in addition to the ones below:

  • Could an assert! be done in a single "core" location that suspension happens that the task is allowed to block? That would be a final check that we did indeed sprinkle all the checks correctly.
  • We'll definitely want a test, in repo, that traps happen as opposed to just updating all existing tests to not trap. I believe Luke has one upstream, but for landing this ahead of the upstream PR could this vendor the test in this repo to ensure we're running it here?

Comment on lines +161 to +162
//
// TODO: Where does async checking happen?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This'll want to get filled out I believe

ty: TypeFuncIndex,
options: OptionsIndex,
storage: &mut [MaybeUninit<ValRaw>],
async_function: bool,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be plumbed through with S as a type parameter rather than an extra argument to follow the same idioms of the other constructors in this file?

Comment on lines +856 to +858
if async_function {
concurrent::check_blocking(store.0)?;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you leave a comment on checks like this to indicate what the trap/check represents?

Comment on lines +2887 to +2889
if !self.options(store, options).async_ {
store.concurrent_state_mut().check_blocking()?;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to host.rs, mind leaving a comment on these checks throughout this file explaining what's going on?

@dicej
Copy link
Contributor Author

dicej commented Dec 5, 2025

Could this ignore the upstream tests temporarily and/or vendor working copies of them?

Yeah; I'll switch the submodule back and temporarily skip the offending tests.

Behavior-wise though there's nothing more you're looking to add here?

Correct; nothing left behavior-wise.

@dicej
Copy link
Contributor Author

dicej commented Dec 5, 2025

  • Could an assert! be done in a single "core" location that suspension happens that the task is allowed to block? That would be a final check that we did indeed sprinkle all the checks correctly.

I'll look into that.

  • We'll definitely want a test, in repo, that traps happen as opposed to just updating all existing tests to not trap. I believe Luke has one upstream, but for landing this ahead of the upstream PR could this vendor the test in this repo to ensure we're running it here?

Yup, I'll just copy the test from his PR into e.g. misc_testsuite.

Copy link
Member

@alexcrichton alexcrichton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh meant to do this too

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

wasmtime:api Related to the API of the `wasmtime` crate itself

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants