From 29e73251e96c64a7f2d167faf43b4d619af6ef20 Mon Sep 17 00:00:00 2001 From: Adam Bratschi-Kaye Date: Thu, 29 Oct 2026 10:24:04 -0400 Subject: [PATCH 1/9] Concurrency: Async lift/lower/effect type summary Add as section in the beginning of Concurrency.md which summarizes the meaning of the various combinations of async lift/lower canonopts with the async function type. --- design/mvp/Concurrency.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/design/mvp/Concurrency.md b/design/mvp/Concurrency.md index 9aefc41d..b6619d1c 100644 --- a/design/mvp/Concurrency.md +++ b/design/mvp/Concurrency.md @@ -128,6 +128,28 @@ Thus, overall, `async` in WIT and the Component Model does not behave like a "color" in the sense described by the popular [What Color Is Your Function?] essay. +The following table summarizes how the behavior of a callee changes, depending +on whether it is `sync` or `async` lifted to a `sync` or `async` component +function type: + +| Component function type | Lift canonical option | Valid? | Effect of callee blocking | Holds instances's exclusive lock? | Can call while instance lock held? | +| ----------------------- | --------------------- | ------ | ------------------ | -------------------- | --------------- | +| `sync` | `sync` | ✅ | Switch to another ready thread in the component instance, trap if there is none | No, but only threads in the same instance and their recursive calls can run until callee returns | Yes | +| `sync` | `async` | ❌ | N/A | N/A | N/A | +| `async` | `sync` | ✅ | Control returns to caller | While running or blocked | No, call waits until lock is released | +| `async` | `async` + callback | ✅ | Control returns to caller | While running, not while blocked | No, waits until lock is released | +| `async` | `async` stackful | ✅ | Control returns to caller | No | Yes | + +The following table summarizes the how behavior of a caller changes, depending on +how it lowers a callee and the type of the callee: + +| Callee component function type | Lower canonical option | Valid? | Effect on caller when callee blocks | +| ------------------------------ | ---------------------- | ------ | ----------------------------------- | +| `sync` | `sync` | ✅ | N/A (Callee traps rather than blocking) | +| `sync` | `async` | ❌ | N/A | +| `async` | `sync` | ✅ | Caller blocks itself | +| `async` | `async` | ✅ | Caller resumes execution - it can await the callee by putting it in a waitable set and also reenter the callee instance | + Each time a component export is called, the wasm runtime logically spawns a new [green thread] (as opposed to a [kernel thread]) to execute the export call concurrently with other calls in the runtime. This means that [thread-local From 0928d59536333b68138d3bce742b7b0220c85525 Mon Sep 17 00:00:00 2001 From: Adam Bratschi-Kaye Date: Fri, 6 Nov 2026 09:40:56 -0500 Subject: [PATCH 2/9] Apply suggestion from @lukewagner Co-authored-by: Luke Wagner --- design/mvp/Concurrency.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/design/mvp/Concurrency.md b/design/mvp/Concurrency.md index b6619d1c..0cbae938 100644 --- a/design/mvp/Concurrency.md +++ b/design/mvp/Concurrency.md @@ -129,8 +129,8 @@ Thus, overall, `async` in WIT and the Component Model does not behave like a essay. The following table summarizes how the behavior of a callee changes, depending -on whether it is `sync` or `async` lifted to a `sync` or `async` component -function type: +on whether `async` is set as a lifting or lowering ABI option and whether the +component function type is `async`: | Component function type | Lift canonical option | Valid? | Effect of callee blocking | Holds instances's exclusive lock? | Can call while instance lock held? | | ----------------------- | --------------------- | ------ | ------------------ | -------------------- | --------------- | From fe7ea230198c331e297442c7915561aa9910ccdf Mon Sep 17 00:00:00 2001 From: Adam Bratschi-Kaye Date: Fri, 6 Nov 2026 09:41:07 -0500 Subject: [PATCH 3/9] Apply suggestion from @lukewagner Co-authored-by: Luke Wagner --- design/mvp/Concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/design/mvp/Concurrency.md b/design/mvp/Concurrency.md index 0cbae938..a0184955 100644 --- a/design/mvp/Concurrency.md +++ b/design/mvp/Concurrency.md @@ -133,7 +133,7 @@ on whether `async` is set as a lifting or lowering ABI option and whether the component function type is `async`: | Component function type | Lift canonical option | Valid? | Effect of callee blocking | Holds instances's exclusive lock? | Can call while instance lock held? | -| ----------------------- | --------------------- | ------ | ------------------ | -------------------- | --------------- | +| ----------------------- | --------------------- | ------ | ------------------------- | --------------------------------- | ---------------------------------- | | `sync` | `sync` | ✅ | Switch to another ready thread in the component instance, trap if there is none | No, but only threads in the same instance and their recursive calls can run until callee returns | Yes | | `sync` | `async` | ❌ | N/A | N/A | N/A | | `async` | `sync` | ✅ | Control returns to caller | While running or blocked | No, call waits until lock is released | From 3b59465a9c44a6bd2a3ffbb3f432733b770a09de Mon Sep 17 00:00:00 2001 From: Adam Bratschi-Kaye Date: Fri, 6 Nov 2026 09:41:25 -0500 Subject: [PATCH 4/9] Apply suggestion from @lukewagner Co-authored-by: Luke Wagner --- design/mvp/Concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/design/mvp/Concurrency.md b/design/mvp/Concurrency.md index a0184955..18188d58 100644 --- a/design/mvp/Concurrency.md +++ b/design/mvp/Concurrency.md @@ -137,7 +137,7 @@ component function type is `async`: | `sync` | `sync` | ✅ | Switch to another ready thread in the component instance, trap if there is none | No, but only threads in the same instance and their recursive calls can run until callee returns | Yes | | `sync` | `async` | ❌ | N/A | N/A | N/A | | `async` | `sync` | ✅ | Control returns to caller | While running or blocked | No, call waits until lock is released | -| `async` | `async` + callback | ✅ | Control returns to caller | While running, not while blocked | No, waits until lock is released | +| `async` | `async` + callback | ✅ | Control returns to caller | While running or blocked on the stack (not when having returned to the event loop) | No, waits until lock is released | | `async` | `async` stackful | ✅ | Control returns to caller | No | Yes | The following table summarizes the how behavior of a caller changes, depending on From 9041f1718234fbac6b5978c4da9c66febe646bd1 Mon Sep 17 00:00:00 2001 From: Adam Bratschi-Kaye Date: Fri, 6 Nov 2026 09:41:34 -0500 Subject: [PATCH 5/9] Apply suggestion from @lukewagner Co-authored-by: Luke Wagner --- design/mvp/Concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/design/mvp/Concurrency.md b/design/mvp/Concurrency.md index 18188d58..97903126 100644 --- a/design/mvp/Concurrency.md +++ b/design/mvp/Concurrency.md @@ -140,7 +140,7 @@ component function type is `async`: | `async` | `async` + callback | ✅ | Control returns to caller | While running or blocked on the stack (not when having returned to the event loop) | No, waits until lock is released | | `async` | `async` stackful | ✅ | Control returns to caller | No | Yes | -The following table summarizes the how behavior of a caller changes, depending on +The following table summarizes how the behavior of a caller changes, depending on how it lowers a callee and the type of the callee: | Callee component function type | Lower canonical option | Valid? | Effect on caller when callee blocks | From e33c4d33e5d229fa68d2bb19e807d43b3055fb06 Mon Sep 17 00:00:00 2001 From: Adam Bratschi-Kaye Date: Fri, 6 Nov 2026 09:41:45 -0500 Subject: [PATCH 6/9] Apply suggestion from @lukewagner Co-authored-by: Luke Wagner --- design/mvp/Concurrency.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/design/mvp/Concurrency.md b/design/mvp/Concurrency.md index 97903126..e87ee9df 100644 --- a/design/mvp/Concurrency.md +++ b/design/mvp/Concurrency.md @@ -146,8 +146,8 @@ how it lowers a callee and the type of the callee: | Callee component function type | Lower canonical option | Valid? | Effect on caller when callee blocks | | ------------------------------ | ---------------------- | ------ | ----------------------------------- | | `sync` | `sync` | ✅ | N/A (Callee traps rather than blocking) | -| `sync` | `async` | ❌ | N/A | -| `async` | `sync` | ✅ | Caller blocks itself | +| `sync` | `async` | ❌ | N/A | +| `async` | `sync` | ✅ | Caller blocks itself | | `async` | `async` | ✅ | Caller resumes execution - it can await the callee by putting it in a waitable set and also reenter the callee instance | Each time a component export is called, the wasm runtime logically spawns a new From f50642dffc14e356bc73a48115fe946ed8fe2730 Mon Sep 17 00:00:00 2001 From: Adam Bratschi-Kaye Date: Fri, 6 Nov 2026 09:41:59 -0500 Subject: [PATCH 7/9] Apply suggestion from @lukewagner Co-authored-by: Luke Wagner --- design/mvp/Concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/design/mvp/Concurrency.md b/design/mvp/Concurrency.md index e87ee9df..b3494173 100644 --- a/design/mvp/Concurrency.md +++ b/design/mvp/Concurrency.md @@ -148,7 +148,7 @@ how it lowers a callee and the type of the callee: | `sync` | `sync` | ✅ | N/A (Callee traps rather than blocking) | | `sync` | `async` | ❌ | N/A | | `async` | `sync` | ✅ | Caller blocks itself | -| `async` | `async` | ✅ | Caller resumes execution - it can await the callee by putting it in a waitable set and also reenter the callee instance | +| `async` | `async` | ✅ | Caller resumes execution - it can await the callee by putting it in a waitable set and also make new calls to the callee instance | Each time a component export is called, the wasm runtime logically spawns a new [green thread] (as opposed to a [kernel thread]) to execute the export call From a864a0018b6e6ef635359edcf9a9684588e7748a Mon Sep 17 00:00:00 2001 From: Adam Bratschi-Kaye Date: Fri, 6 Nov 2026 09:43:35 -0500 Subject: [PATCH 8/9] remove backticks around sync/async --- design/mvp/Concurrency.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/design/mvp/Concurrency.md b/design/mvp/Concurrency.md index b3494173..531c38f3 100644 --- a/design/mvp/Concurrency.md +++ b/design/mvp/Concurrency.md @@ -134,21 +134,21 @@ component function type is `async`: | Component function type | Lift canonical option | Valid? | Effect of callee blocking | Holds instances's exclusive lock? | Can call while instance lock held? | | ----------------------- | --------------------- | ------ | ------------------------- | --------------------------------- | ---------------------------------- | -| `sync` | `sync` | ✅ | Switch to another ready thread in the component instance, trap if there is none | No, but only threads in the same instance and their recursive calls can run until callee returns | Yes | -| `sync` | `async` | ❌ | N/A | N/A | N/A | -| `async` | `sync` | ✅ | Control returns to caller | While running or blocked | No, call waits until lock is released | -| `async` | `async` + callback | ✅ | Control returns to caller | While running or blocked on the stack (not when having returned to the event loop) | No, waits until lock is released | -| `async` | `async` stackful | ✅ | Control returns to caller | No | Yes | +| `sync` | sync | ✅ | Switch to another ready thread in the component instance, trap if there is none | No, but only threads in the same instance and their recursive calls can run until callee returns | Yes | +| `sync` | async | ❌ | N/A | N/A | N/A | +| `async` | sync | ✅ | Control returns to caller | While running or blocked | No, call waits until lock is released | +| `async` | async + callback | ✅ | Control returns to caller | While running or blocked on the stack (not when having returned to the event loop) | No, waits until lock is released | +| `async` | async stackful | ✅ | Control returns to caller | No | Yes | The following table summarizes how the behavior of a caller changes, depending on how it lowers a callee and the type of the callee: | Callee component function type | Lower canonical option | Valid? | Effect on caller when callee blocks | | ------------------------------ | ---------------------- | ------ | ----------------------------------- | -| `sync` | `sync` | ✅ | N/A (Callee traps rather than blocking) | -| `sync` | `async` | ❌ | N/A | -| `async` | `sync` | ✅ | Caller blocks itself | -| `async` | `async` | ✅ | Caller resumes execution - it can await the callee by putting it in a waitable set and also make new calls to the callee instance | +| `sync` | sync | ✅ | N/A (Callee traps rather than blocking) | +| `sync` | async | ❌ | N/A | +| `async` | sync | ✅ | Caller blocks itself | +| `async` | async | ✅ | Caller resumes execution - it can await the callee by putting it in a waitable set and also make new calls to the callee instance | Each time a component export is called, the wasm runtime logically spawns a new [green thread] (as opposed to a [kernel thread]) to execute the export call From b50ae4ec050770033b164ba426940b297d3355d5 Mon Sep 17 00:00:00 2001 From: Adam Bratschi-Kaye Date: Mon, 9 Nov 2026 22:44:47 -0500 Subject: [PATCH 9/9] remove backticks in first column --- design/mvp/Concurrency.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/design/mvp/Concurrency.md b/design/mvp/Concurrency.md index 531c38f3..bc037864 100644 --- a/design/mvp/Concurrency.md +++ b/design/mvp/Concurrency.md @@ -134,21 +134,21 @@ component function type is `async`: | Component function type | Lift canonical option | Valid? | Effect of callee blocking | Holds instances's exclusive lock? | Can call while instance lock held? | | ----------------------- | --------------------- | ------ | ------------------------- | --------------------------------- | ---------------------------------- | -| `sync` | sync | ✅ | Switch to another ready thread in the component instance, trap if there is none | No, but only threads in the same instance and their recursive calls can run until callee returns | Yes | -| `sync` | async | ❌ | N/A | N/A | N/A | -| `async` | sync | ✅ | Control returns to caller | While running or blocked | No, call waits until lock is released | -| `async` | async + callback | ✅ | Control returns to caller | While running or blocked on the stack (not when having returned to the event loop) | No, waits until lock is released | -| `async` | async stackful | ✅ | Control returns to caller | No | Yes | +| sync | sync | ✅ | Switch to another ready thread in the component instance, trap if there is none | No, but only threads in the same instance and their recursive calls can run until callee returns | Yes | +| sync | async | ❌ | N/A | N/A | N/A | +| async | sync | ✅ | Control returns to caller | While running or blocked | No, call waits until lock is released | +| async | async + callback | ✅ | Control returns to caller | While running or blocked on the stack (not when having returned to the event loop) | No, waits until lock is released | +| async | async stackful | ✅ | Control returns to caller | No | Yes | The following table summarizes how the behavior of a caller changes, depending on how it lowers a callee and the type of the callee: | Callee component function type | Lower canonical option | Valid? | Effect on caller when callee blocks | | ------------------------------ | ---------------------- | ------ | ----------------------------------- | -| `sync` | sync | ✅ | N/A (Callee traps rather than blocking) | -| `sync` | async | ❌ | N/A | -| `async` | sync | ✅ | Caller blocks itself | -| `async` | async | ✅ | Caller resumes execution - it can await the callee by putting it in a waitable set and also make new calls to the callee instance | +| sync | sync | ✅ | N/A (Callee traps rather than blocking) | +| sync | async | ❌ | N/A | +| async | sync | ✅ | Caller blocks itself | +| async | async | ✅ | Caller resumes execution - it can await the callee by putting it in a waitable set and also make new calls to the callee instance | Each time a component export is called, the wasm runtime logically spawns a new [green thread] (as opposed to a [kernel thread]) to execute the export call