33This document contains a high-level summary of the native concurrency support
44added as part of [ WASI Preview 3] , providing background for understanding the
55definitions in the [ WIT] , [ AST explainer] , [ binary format] and [ Canonical ABI
6- explainer] documents that are gated by the 🔀 (async) and 🧵 (threading)
7- emojis. For an even higher-level introduction, see [ these] [ wasmio-2024 ]
8- [ presentations] [ wasmio-2025 ] .
6+ explainer] documents that are gated by the 🔀 (async) and 🧵 (threading) emojis.
97
108* [ Goals] ( #goals )
119* [ Summary] ( #summary )
@@ -56,8 +54,8 @@ concurrency-specific goals and use cases:
5654* Allow polyfilling in browsers via JavaScript Promise Integration ([ JSPI] )
5755* Avoid partitioning interfaces and components into separate ecosystems based
5856 on degree of concurrency; don't give components a "[ color] ".
59- * Maintain meaningful cross-language call stacks (for the benefit of debugging,
60- logging and tracing ).
57+ * Allow runtimes to maintain meaningful cross-language call stacks (for the
58+ benefit of debugging, logging, tracing and profiling ).
6159* Consider backpressure and cancellation as part of the design.
6260* Allow non-reentrant synchronous and event-loop-driven core wasm code that
6361 assumes a single global linear memory stack to not have to worry about
@@ -120,13 +118,14 @@ language's style of concurrency, most `world`s (including `wasi:cli/command`,
120118functions so that the contained Core WebAssembly code is free to block.
121119Implementing a non-` async ` function will primarily only arise when a component
122120is * virtualizing* the non-` async ` * imports* of a ` world ` (e.g., the getters and
123- setters of ` wasi:http/types.headers ` ). In this virtualization scenario (once
124- functions are allowed to be [ recursive] ( #TODO ) ), the Canonical ABI and/or Core
125- WebAssembly [ stack-switching] proposal will allow a parent component to
126- implement a child's non-` async ` imports in terms of the parent's ` async `
127- imports in the same manner as [ JSPI] . Thus, overall, ` async ` in WIT and the
128- Component Model does not behave like a "color" in the sense described by the
129- popular [ What Color Is Your Function?] essay.
121+ setters of ` wasi:http/types.headers ` ). In this more exotic virtualization
122+ scenario, a [ future extension] ( #TODO ) could allow a parent component that
123+ imports ` async ` functions to implement its child's non-` async ` imports in the
124+ same manner as [ JSPI] in the browser.
125+
126+ Thus, overall, ` async ` in WIT and the Component Model does not behave like a
127+ "color" in the sense described by the popular [ What Color Is Your Function?]
128+ essay.
130129
131130Each time a component export is called, the wasm runtime logically spawns a new
132131[ green thread] (as opposed to a [ kernel thread] ) to execute the export call
@@ -190,18 +189,23 @@ immediately block.
190189This backpressure mechanism provides the basis for how the sync and async ABIs
191190interoperate:
1921911 . If a component calls an import using the async ABI, and the import is
193- implemented by a component using the sync ABI, and the callee blocks,
194- execution is immediately transferred back to the caller (as required by the
195- async ABI) and the callee's component instance is marked "suspended".
196- 2 . If another async call attempts to start in a "suspended" component instance,
197- the Component Model automatically makes the call block, the same way as when
198- backpressure is active.
192+ implemented by a component using the sync ABI, the callee first acquires
193+ an "exclusive" on the component instance, and then starts executing. If
194+ the callee blocks, execution is immediately transferred back to the caller
195+ (as required by the async ABI).
196+ 2 . If another async call attempts to start in this same component instance, the
197+ callee immediately block when acquiring the "exclusive" lock, waiting for the
198+ previous call to return and release the lock.
199199
200200Note that because functions without ` async ` in their type are not allowed to
201- block, non-` async ` functions do not check for backpressure or suspension; they
202- always run synchronously . Components exporting a mix of ` async ` and non-` async `
201+ block, non-` async ` functions do not attempt to acquire the "exclusive" lock;
202+ they just barge in . Components exporting a mix of ` async ` and non-` async `
203203functions (which again mostly only arises in the more advanced virtualization
204- scenarios) must thus take care to handle non-` async ` reentrance gracefully.
204+ scenarios) must therefore take care to handle the "barges in" case gracefully.
205+ Because this nested non-` async ` call will complete synchronously without
206+ blocking, this behavior does not break [ component invariant] #3 since a single
207+ global shadow stack can still be (re)used in a LIFO manner to implement the
208+ nested synchronous call in much the same manner as a traditional signal handler.
205209
206210Lastly, WIT is extended with two new type constructors—` future<T> ` and
207211` stream<T> ` —to allow new WIT interfaces to explicitly represent concurrency in
@@ -314,20 +318,14 @@ of the new subtask created for the import call. Thus, one reason for
314318associating every thread with a "containing task" is to ensure that there is
315319always a well-defined async call stack.
316320
317- A semantically-observable use of the async call stack is to distinguish between
318- hazardous ** recursive reentrance** , in which a component instance is reentered
319- when one of its tasks is already on the callstack, from business-as-usual
320- ** sibling reentrance** , in which a component instance is reentered for the
321- first time on a particular async call stack. Recursive reentrance currently
322- always traps, but will be allowed (and indicated to core wasm) in an opt-in
323- manner in the [ future] ( #TODO ) .
324-
325- The async call stack is also useful for non-semantic purposes such as providing
326- backtraces when debugging, profiling and tracing. While particular languages
327- can and do maintain their own async call stacks in core wasm state, without the
328- Component Model's async call stack, linkage * between* different languages would
329- be lost at component boundaries, leading to a loss of overall context in
330- multi-component applications.
321+ The async call stack is not currently semantically observable to the running
322+ components other than possibly, nondeterministically, as part of the callstack
323+ stored in 📝 ` error-context ` . But this async call stack is also useful for
324+ other purposes such as providing backtraces when debugging, profiling and
325+ tracing. While particular languages can and do maintain their own async call
326+ stacks in core wasm state, without the Component Model's async call stack,
327+ linkage * between* different languages would be lost at component boundaries,
328+ leading to a loss of overall context in multi-component applications.
331329
332330There is an important gap between the Component Model's minimal form of
333331Structured Concurrency and the Structured Concurrency support that appears in
@@ -489,7 +487,11 @@ all of which are described above or below in more detail:
489487 [ ` subtask.cancel ` ] ( #cancellation ) built-in
490488
491489At each of these points, the [ current thread] ( #current-thread-and-task ) will be
492- suspended and execution will transfer to a caller's thread, if there is one.
490+ suspended and execution will transfer to a caller's thread, if there is one, or
491+ if not, the runtime, which may invoke new component exports or
492+ nondeterministically select a cooperative thread that is ready to run and resume
493+ it. Thus, each of these represents ** cooperative yield points** .
494+
493495Additionally, each of these potentially-blocking operations will trap if the
494496[ current task's function type] ( #current-thread-and-task ) does not declare the
495497` async ` effect, since only ` async ` -typed functions are allowed to block. As an
@@ -1379,9 +1381,9 @@ comes after:
13791381 type to block during instantiation
13801382* add an ` async ` effect on ` resource ` type definitions allowing a resource
13811383 type to block during its destructor
1382- * ` recursive ` function type attribute: allow a function to opt in to
1383- recursive [ reentrance ] , extending the ABI to link the inner and
1384- outer activations
1384+ * allow a parent component to perform [ JSPI ] -like suspension of the sync calls
1385+ of its child components, thereby allowing the parent to implement the child's
1386+ sync imports calls in terms of the parent's ` async ` imports.
13851387* add a ` strict-callback ` option that adds extra trapping conditions to
13861388 provide the semantic guarantees needed for engines to statically avoid
13871389 fiber creation at component-to-component ` async ` call boundaries
@@ -1391,9 +1393,6 @@ comes after:
13911393 ` shared `
13921394
13931395
1394- [ wasmio-2024 ] : https://www.youtube.com/watch?v=y3x4-nQeXxc
1395- [ wasmio-2025 ] : https://www.youtube.com/watch?v=mkkYNw8gTQg
1396-
13971396[ Color ] : https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/
13981397[ What Color Is Your Function? ] : https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/
13991398[ Weak Memory Model ] : https://people.mpi-sws.org/~rossberg/papers/Watt,%20Rossberg,%20Pichon-Pharabod%20-%20Weakening%20WebAssembly%20[Extended].pdf
@@ -1426,6 +1425,7 @@ comes after:
14261425
14271426[ AST Explainer ] : Explainer.md
14281427[ Canonical Built-in ] : Explainer.md#canonical-built-ins
1428+ [ Component Invariant ] : Explainer.md#component-invariant
14291429[ `context.get` ] : Explainer.md#-contextget
14301430[ `context.set` ] : Explainer.md#-contextset
14311431[ `backpressure.inc` ] : Explainer.md#-backpressureinc-and-backpressuredec
@@ -1463,7 +1463,6 @@ comes after:
14631463[ Binary Format ] : Binary.md
14641464[ WIT ] : WIT.md
14651465[ Blast Zone ] : FutureFeatures.md#blast-zones
1466- [ Reentrance ] : Explainer.md#component-invariants
14671466[ `start` ] : Explainer.md#start-definitions
14681467
14691468[ Store ] : https://webassembly.github.io/spec/core/exec/runtime.html#syntax-store
0 commit comments