Skip to content

Fix some cooperative thread limitations - #656

Merged
lukewagner merged 1 commit into
mainfrom
fix-coop
May 29, 2026
Merged

Fix some cooperative thread limitations#656
lukewagner merged 1 commit into
mainfrom
fix-coop

Conversation

@lukewagner

Copy link
Copy Markdown
Member

@TartanLlama's work implementing pthreads in wasi-libc highlighted a few limitations with cooperative threads as currently spec'd that this PR intends to address:

  • If pthreads are implemented using cooperative threads in sync-typed context, they won't work (due to trapping or no-op yielding) in cases where, if they had instead been implemented via CPS transform (like Asyncify), they could have.
  • pthread APIs like pthread_joinwould like to be able to switch to a thread if that thread is ready to run, but not trap if it's not ready-to-run, b/c the current state of the thread isn't known.

The first bullet suggests replacing the strict "may_block" traps (and the no-op special case in thread.yield) with a more permissive approach where: if a thread blocks (now better-defined after #637) as part of a sync-typed call, but there are other threads in the same component instance that are ready-to-run, they are resumed directly, and repeatedly, until either there are no more ready threads (in which case trap, b/c it's actually blocked) or a value is returned successfully to the caller. This also implicitly addresses the limitation @badeend just pointed out in #651, since blocking is fine as long as there is some other thread that can make progress. (E.g., maybe the blocking call was just doing some asynchronous logging off the critical path.) The "in the same component instance" caveat matches the expressivity of a core wasm CPS transform and is also necessary to maintain the reentrance invariant (re)defined in #650.

This does have the unfortunate side effect of allowing more code to accidentally depend on non-portable behavior (whether various operations actually block in practice), but this is already quite possible when using the async ABI and it's sortof just the nature of concurrency.

The second bullet suggests first renaming (but otherwise keeping the exact same behavior):

  • thread.switch-to => thread.suspend-then-resume = resume other thread (trap if it's not "suspended"), leave current thread "suspended"
  • thread.yield-to => thread.yield-then-resume = resume other thread (trap if it's not "suspended"), leave current thread "ready"

and then symmetrically add two new variants:

  • thread.suspend-then-promote = resume other thread if it's "ready", leave current thread "suspended"
  • thread.yield-then-promote = resume other thread if it's "ready", leave current thread "ready"

Thus, if the other thread is not "ready", thread.{suspend,yield}-then-promote behave the same as thread.{suspend,yield}.

@lukewagner

Copy link
Copy Markdown
Member Author

Since cooperative threads are gated and experimental, I'll merge this for now; happy to iterate on the design in future issues/PRs.

@lukewagner
lukewagner merged commit 823aa13 into main May 29, 2026
2 checks passed
@lukewagner
lukewagner deleted the fix-coop branch May 29, 2026 19:55
alexcrichton added a commit to alexcrichton/wasm-tools that referenced this pull request Jul 1, 2026
This commit synchronizes `cm-threading` intrinsics parsed by
wasmparser/tooling/etc to match the current specification. These
intentionally diverged from the specification in bytecodealliance#2430 and when the
specification was updated in WebAssembly/component-model#656 it ended up
settling on some minor adjustments. This additionally takes into account
WebAssembly/component-model#674 for binary parsing adjustments.
lukewagner pushed a commit that referenced this pull request Jul 1, 2026
* Synchronize `Binary.md` threading intrinsics

In #656 the threading-related intrinsics were revised and updated, but
`Binary.md` wasn't updated in the same PR. This commit removes the
removed intrinsics (`thread.switch-to` and `thread.yield-to`),
reorganizes the list slightly (moves `thread.yield` down), and then
renumbers the remaining intrinsics.

* Flag `thread.yield` under the async feature gate

This matches what wasm-tools/Wasmtime do at least which is
`thread.yield` is supported with just the component-model-async feature
and doesn't need component-model-threading. IIRC this is due to the fact
of this intrinsic existing prior to component-model-threading and it was
just renamed later on.
github-merge-queue Bot pushed a commit to bytecodealliance/wasm-tools that referenced this pull request Jul 1, 2026
This commit synchronizes `cm-threading` intrinsics parsed by
wasmparser/tooling/etc to match the current specification. These
intentionally diverged from the specification in #2430 and when the
specification was updated in WebAssembly/component-model#656 it ended up
settling on some minor adjustments. This additionally takes into account
WebAssembly/component-model#674 for binary parsing adjustments.
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.

2 participants