Skip to content

align multithreading and trap behavior with CM spec - #14146

Open
dicej wants to merge 7 commits into
bytecodealliance:mainfrom
dicej:spec-threading-and-sync-blocking-updates
Open

align multithreading and trap behavior with CM spec#14146
dicej wants to merge 7 commits into
bytecodealliance:mainfrom
dicej:spec-threading-and-sync-blocking-updates

Conversation

@dicej

@dicej dicej commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

This updates Wasmtime's Component Model async and cooperative multithreading support to match the current specification, including:

  • Refined rules for trapping when a sync-typed function blocks. We now enforce this "lazily" rather than "eagerly", mwaning a sync-typed function is allowed to call an async-typed function or blocking intrinsic, and if it doesn't actually block, we won't trap. And if the call does block, we will look for any eligible threads to run and run them until no such threads remain, only trapping if and when we still need to block and have no more threads to run.

  • Ensure that the predicate for determining which threads can be run when a sync-typed function is executing in an instance matches the spec.

  • Remove the previous "may block" bookkeeping at the task and root instance level, replacing it with (sub-)instance level tracking of whether any sync-typed function is running in that instance.

  • Run the event loop during start function calls since they are now allowed to call async-typed functions, create and resume threads, etc.

Note that this includes test/component-model submodule updates which haven't yet been merged to the main branch of the upstream repo, but should be merged soon. See WebAssembly/component-model#696

Fixes #14117

@dicej
dicej requested a review from alexcrichton August 17, 2026 15:48
@dicej
dicej force-pushed the spec-threading-and-sync-blocking-updates branch 3 times, most recently from 8506000 to 5d88b4c Compare August 17, 2026 17:22

@alexcrichton alexcrichton left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to review more of concurrent.rs but here's some initial thoughts. It's at the point where whenever I expand context on github it just sends me randomly elsewhere in this diff and I keep losing my spot in the otherwise big diff in concurrent.rs. I'm hoping my changes in dicej#7 which reduce the number of files changed helps with that...

Comment thread crates/wasmtime/src/runtime/component/concurrent.rs Outdated
Comment thread crates/wasmtime/src/runtime/component/instance.rs Outdated
Comment thread crates/wasmtime/src/runtime/component/instance.rs Outdated
Comment thread crates/wasmtime/src/runtime/component/instance.rs Outdated
Comment thread crates/wasmtime/src/runtime/component/instance.rs
Comment thread crates/wasmtime/src/runtime/instance.rs Outdated
Comment thread crates/wasmtime/src/runtime/component/concurrent.rs
@github-actions github-actions Bot added the wasmtime:api Related to the API of the `wasmtime` crate itself label Aug 18, 2026
Comment thread crates/wasmtime/src/runtime/component/concurrent.rs Outdated
Comment thread crates/wasmtime/src/runtime/component/concurrent.rs
Comment thread crates/wasmtime/src/runtime/component/concurrent.rs
@alexcrichton

Copy link
Copy Markdown
Member

I think this may also still have lingering management of may_block as it looks like there's some here too

@dicej
dicej force-pushed the spec-threading-and-sync-blocking-updates branch 3 times, most recently from 6a0209e to 25af96d Compare August 28, 2026 14:09
@dicej
dicej force-pushed the spec-threading-and-sync-blocking-updates branch 2 times, most recently from 29ac4ee to b045d7e Compare August 28, 2026 19:32
@dicej
dicej requested a review from alexcrichton August 28, 2026 19:32
@dicej

dicej commented Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

@alexcrichton would you mind taking one more look at this? Aligning it with WebAssembly/component-model#705 required an overhaul and uncovered a few subtle divergences with the spec which I had to address.

dicej and others added 6 commits August 28, 2026 13:37
This updates Wasmtime's Component Model async and cooperative multithreading
support to match the current specification, including:

- Refined rules for trapping when a sync-typed function blocks.  We now enforce
  this "lazily" rather than "eagerly", mwaning a sync-typed function is allowed
  to call an async-typed function or blocking intrinsic, and if it doesn't
  actually block, we won't trap.  And if the call _does_ block, we will look for
  any eligible threads to run and run them until no such threads remain, only
  trapping if and when we still need to block and have no more threads to run.

- Allow reentrance in all cases except when the instance has trapped.

- Remove the previous "may block" bookkeeping at the task and root instance
  level, replacing it with (sub-)instance level tracking of whether any
  sync-typed function is running in that instance.

- Run the event loop during start function calls since they are now allowed to
  call async-typed functions, create and resume threads, etc.  I've also added
  some code to assert that the event loop is running when it is required.

- Add `ConcurrentState::switch_item` for use when we need to run a specific work
  item at the next turn of the event loop, regardless of what's already in the
  `high_priority` queue.  This is necessary because the spec is particular about
  which thread to switch to e.g. when calling a function or promoting a thread,
  and it won't allow us to run any other threads first.

Note that this includes `test/component-model` submodule updates which haven't
yet been merged to the main branch of the upstream repo, but should be merged
soon.  See WebAssembly/component-model#705

Fixes bytecodealliance#14117

Co-authored-by: Alex Crichton <[email protected]>
Accept an `unsafe` block which I believe is correct and still otherwise
safe at the invocation site. The main hidden constraint now is that we
can't transfer fibers to other non-store-bound-locations but that's
effectively already true so shouldn't be too onerous to uphold.
- Ensure that subtask status updates are delivered promptly and
  deterministically according to the spec by using
  `ConcurrentState::switch_item` instead of `ConcurrentState::high_priority`

- Fix reentrance scenarious involving `subtask.cancel` where the subtask tries
  to add itself to a waitable set before or after being canceled

- Refine rules for switching-or-trapping on thread exit when the current
  instance has a sync-typed call in progress

- Misc. bug fixes
Notably, this makes Wasmtime more aggressive about poisoning the store if an
error happens when e.g. lifting a result (e.g. due to a misaligned pointer), and
the tests have been updated accordingly.
@dicej
dicej force-pushed the spec-threading-and-sync-blocking-updates branch from b045d7e to f511826 Compare August 28, 2026 19:42
@dicej
dicej marked this pull request as ready for review August 28, 2026 19:42
@dicej
dicej requested review from a team as code owners August 28, 2026 19:42
Comment thread crates/wasmtime/src/runtime/component/instance.rs
Comment thread crates/wasmtime/src/runtime/component/concurrent.rs
Comment thread crates/wasmtime/src/runtime/component/concurrent.rs
Ok(())
}

fn any_may_not_suspend(&mut self) -> Result<bool> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This feels pretty bad as it's a linear search over everything in the concurrent table. Could this be managed with a counter of some kind instead or something like that?

@dicej dicej Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is only used when we're about trap due to a deadlock situation, so I figured it isn't performance sensitive. With that in mind, do you still think it should be optimized?

Comment thread crates/wasmtime/src/runtime/component/concurrent.rs Outdated
Comment on lines +4246 to +4247
Some(WaitMode::Caller { .. }) => {
bail_bug!("unexpected `WaitMode::Caller` in wake_on_cancel set")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

An observation on this: if this is actually hit it'll destroy the process due to one of the fields in the .. being a fiber that can't be dropped.

That being said this is actually present in a whole bunch of places throughout this file. In a myriad of locations where there's a fiber in scope there are instances of ? used, which only trigger on bugs, but if they were to occur would also destroy the fiber. I'm not entirely sure what to do about that, but we may want to track that as a general issue of something to improve at some point.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I know I've said this before, but if you're for helping out at some point in the future this file really could benefit from being split up. It's kind of unreviewable in github's UI because if context is expanded anywhere then the UI jumps to some random position in the diff-of-all-files, meaning you can't actually keep your place in this file. That's almost surely a UI bug on github's side, but I think this file would benefit from being split up for a number of other reasons too.

Comment on lines +5350 to +5366
if let Some(Event::Subtask {
status: Status::Starting,
}) = &self.common(state)?.event
{
// `Status::Starting` means we can't invoke the
// callee yet due to e.g. backpressure, so go ahead
// and deliver the update now.
state.set_switch_item(item)?;
} else {
if state.get_mut(callee)?.switch_item.is_some() {
bail_bug!(
"`GuestTask::switch_item` is already `Some(_)` when we need \
to deliver a subtask status update to the caller"
);
}
state.get_mut(callee)?.switch_item = Some(item);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think both of these branches boil down to set_switch_item, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

One is setting the switch item on the store, while the other is setting in on the task; i.e. they're two different fields. The latter is used to defer setting the store's switch item until the task either suspends or exits.

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.

[async] non-async-typed function behavior diverges from spec in two cases

2 participants