@@ -74,16 +74,6 @@ the same way that they already bind to various OS's concurrent I/O APIs (such
7474as ` select ` , ` epoll ` , ` io_uring ` , ` kqueue ` and Overlapped I/O) making the
7575Component Model "just another OS" from the language toolchain's perspective.
7676
77- The new async ABI can be used alongside or instead of the existing Preview 2
78- "sync ABI" to call or implement * any* WIT function type. When * calling* an
79- imported function via the async ABI, if the callee [ blocks] ( #blocking ) , control
80- flow is returned immediately to the caller, and the callee continues executing
81- concurrently. When * implementing* an exported function via the async ABI,
82- multiple concurrent export calls are allowed to be made by the caller.
83- Critically, both sync-ABI-calls-async-ABI and async-ABI-calls-sync-ABI pairings
84- have well-defined, composable behavior for both inter-component and
85- intra-component calls.
86-
8777In addition to adding a new async * ABI* for use by the language's compiler and
8878runtime, the Component Model also adds a new ` async ` [ effect type] that can be
8979added to function types (in both WIT and raw component function type
@@ -103,6 +93,16 @@ invariant is necessary to allow non-`async` component exports to be called in
10393synchronous contexts (like event listeners, callbacks, getters, setters and
10494constructors).
10595
96+ The new async ABI can be used alongside or instead of the existing Preview 2
97+ "sync ABI" to call or implement any ` async ` -typed functions. When * calling* an
98+ imported function via the async ABI, if the ` async ` callee [ blocks] ( #blocking ) ,
99+ control flow is returned immediately to the caller, and the callee continues
100+ executing concurrently. When * implementing* an ` async ` function via the async
101+ ABI, multiple concurrent export calls are allowed to be made by the caller.
102+ Critically, both sync-ABI-calls-async-ABI and async-ABI-calls-sync-ABI pairings
103+ have well-defined, composable behavior for both inter-component and
104+ intra-component calls.
105+
106106Because ` async ` function exports may be implemented with the * sync* ABI and
107107then call ` async ` function imports using the * sync* ABI, traditional sync code
108108can compile directly to components exporting ` async ` functions without having
@@ -685,30 +685,31 @@ the "started" state.
685685
686686### Returning
687687
688- The way an async export call returns its value is by calling [ ` task.return ` ] ,
689- passing the core values that are to be lifted as * parameters* .
688+ The way an ` async ` export returns its value using the async ABI is by calling
689+ [ ` task.return ` ] , passing the core values that are to be lifted as * parameters* .
690+ When using the async ABI, * any* of the threads contained by a task can call
691+ ` task.return ` ; there is no "main thread" of a task. When the last thread of a
692+ task returns, there is a trap if ` task.return ` has not been called. Thus, * some*
693+ thread (either the thread created implicitly for the initial export call or some
694+ thread transitively created by that thread) must call ` task.return ` .
690695
691696Returning values by calling ` task.return ` allows a task to continue executing
692- even after it has passed its initial results to the caller. This can be useful
693- for various finalization tasks (freeing memory or performing logging, billing
694- or metrics operations) that don't need to be on the critical path of returning
695- a value to the caller, but the major use of executing code after ` task.return `
696- is to continue to read and write from streams and futures. For example, a
697- stream transformer function of type ` func(in: stream<T>) -> stream<U> ` will
698- immediately ` task.return ` a stream created via ` stream.new ` and then sit in a
699- loop interleaving ` stream.read ` s (of the readable end passed for ` in ` ) and
700- ` stream.write ` s (of the writable end it ` stream.new ` ed) before exiting the
701- task.
702-
703- * Any* of the threads contained by a task can call ` task.return ` ; there is no
704- "main thread" of a task. When the last thread of a task returns, there is a
705- trap if ` task.return ` has not been called. Thus, * some* thread (either the
706- thread created implicitly for the initial export call or some thread
707- transitively created by that thread) must call ` task.return ` .
697+ even after it has passed its initial results to the caller. This is also
698+ possible even with the sync ABI by using cooperative threads. Continuing
699+ to execute after returning a value can be useful for various finalization tasks
700+ (freeing memory or performing logging, billing or metrics operations) that don't
701+ need to be on the critical path of returning a value to the caller, but the
702+ major use of executing code after ` task.return ` is to continue to read and write
703+ from streams and futures. For example, a stream transformer function of type
704+ ` func(in: stream<T>) -> stream<U> ` will immediately ` task.return ` a stream
705+ created via ` stream.new ` and then sit in a loop interleaving ` stream.read ` s (of
706+ the readable end passed for ` in ` ) and ` stream.write ` s (of the writable end it
707+ ` stream.new ` ed) before exiting the task.
708708
709709Once ` task.return ` is called, the task is in the "returned" state. Calling
710- ` task.return ` when not in the "started" state traps. Once in a "returned"
711- state, non-` async ` functions are allowed to block.
710+ ` task.return ` when not in the "started" state traps. Once in a "returned" state,
711+ non-` async ` functions may block using cooperative threads that were created
712+ before the synchronous task's implicit thread returned.
712713
713714### Borrows
714715
@@ -873,19 +874,12 @@ JS [top-level `await`] or I/O in C++ constructors executing during `start`.
873874
874875## Async ABI
875876
876- At an ABI level, native async in the Component Model defines for every WIT
877- function an async-oriented core function signature that can be used instead of
878- or in addition to the existing (Preview-2-defined) synchronous core function
879- signature. This async-oriented core function signature is intended to be called
880- or implemented by generated bindings which then map the low-level core async
881- protocol to the languages' higher-level native concurrency features.
882-
883- Note that * every* WIT-level function type can be lifted and lowered using the
884- async (or sync) ABI. While calling a non-` async ` -typed function import using
885- the async ABI will never returned that the call "blocked" (as guaranteed by the
886- Component Model trapping if the callee would have blocked), the async ABI is
887- still allowed to be used (for the benefit of code generators that only want
888- to think about one ABI).
877+ At an ABI level, native async in the Component Model defines for every
878+ ` async ` -typed function a non-blocking core function signature that can be
879+ used instead of or in addition to the existing (Preview-2-defined) synchronous
880+ core function signature. This non-blocking core function signature is intended
881+ to be called or implemented by generated bindings which then map the low-level
882+ core async protocol to the languages' higher-level native concurrency features.
889883
890884### Async Import ABI
891885
0 commit comments