@@ -11,9 +11,9 @@ emojis. For an even higher-level introduction, see [these][wasmio-2024]
1111* [ Summary] ( #summary )
1212* [ Concepts] ( #concepts )
1313 * [ Threads and Tasks] ( #threads-and-tasks )
14+ * [ Subtasks and Supertasks] ( #subtasks-and-supertasks )
1415 * [ Current Thread and Task] ( #current-thread-and-task )
1516 * [ Thread-Local Storage] ( #thread-local-storage )
16- * [ Structured concurrency] ( #structured-concurrency )
1717 * [ Streams and Futures] ( #streams-and-futures )
1818 * [ Stream Readiness] ( #stream-readiness )
1919 * [ Waiting] ( #waiting )
@@ -236,76 +236,17 @@ Thread
236236where a ** component store** is the top-level "thing" and analogous to a Core
237237WebAssembly [ store] .
238238
239- The reason for the thread/task split is so that, when one thread creates a new
240- thread by calling [ ` thread.new-indirect ` ] , the new thread is contained by the
241- task of the original thread. Thus there is an N:1 relationship between threads
242- and tasks that ties N threads to the original export call (= "task") that
243- transitively spawned those N threads. This relationship serves several purposes
244- described in the following sections.
239+ The reason for the thread/task split is that, when one thread creates a new
240+ thread, the new thread is contained by the task of the original thread which
241+ creates an N:1 relationship between threads and tasks that ties N threads to
242+ the original export call (= "task") that transitively spawned those N threads.
243+ This relationship serves several purposes described in the following sections.
245244
246245In the Canonical ABI explainer, threads, tasks, component instances and
247246component stores are represented by the [ ` Thread ` ] , [ ` Task ` ] ,
248247[ ` ComponentInstance ` ] and [ ` Store ` ] classes, resp.
249248
250- ### Current Thread and Task
251-
252- At any point in time while executing Core WebAssembly code or a [ canonical
253- built-in] called by Core WebAssembly code, there is a well-defined ** current
254- thread** whose containing task is the ** current task** . The "current thread" is
255- modelled in the Canonical ABI's Python code by explicitly passing a [ ` Thread ` ]
256- object as an argument to all function calls so that the semantic "current
257- thread" is always the value of the ` thread ` parameter. Threads store their
258- containing task so that the "current task" is always ` thread.task ` .
259-
260- ### Thread-Local Storage
261-
262- Each thread contains a distinct mutable ** thread-local storage** array. The
263- current thread's thread-local storage can be read and written from core wasm
264- code by calling the [ ` context.get ` ] and [ ` context.set ` ] built-ins.
265-
266- The thread-local storage array's length is currently fixed to contain exactly
267- 2 ` i32 ` s with the goal of allowing this array to be stored inline in whatever
268- existing runtime data structure is already efficiently reachable from ambient
269- compiled wasm code. Because module instantiation is declarative in the
270- Component Model, the imported ` context.{get,set} ` built-ins can be inlined by
271- the core wasm compiler as-if they were instructions, allowing the generated
272- machine code to be a single load or store. This makes thread-local storage a
273- natural place to store:
274- 1 . a pointer to the linear-memory "shadow stack" pointer
275- 2 . a pointer to a struct used by the runtime to implement the language's
276- thread-local features
277-
278- When threads are created explicitly by ` thread.new-indirect ` , the lifetime of
279- the thread-local storage array ends when the function passed to
280- ` thread.new-indirect ` returns and thus any linear-memory allocations associated
281- with the thread-local storage array should be eagerly freed by guest code right
282- before returning. Similarly, since each call to an export logically creates a
283- fresh thread, thread-local allocations can be eagerly released when this
284- implicit thread exits by returning from the exported function or, if the
285- stackless async ABI is used, returning the "exit" code to the event loop. This
286- non-reuse of thread-local storage between distinct export calls avoids what
287- would otherwise be a likely source of TLS-related memory leaks.
288-
289- When [ memory64] is integrated into the Component Model's Canonical ABI,
290- ` context.{get,set} ` will be backwards-compatibly relaxed to allow ` i64 `
291- pointers (overlaying the ` i32 ` values like hardware 32/64-bit registers). When
292- [ wasm-gc] is integrated, these integral context values can serve as indices
293- into guest-managed tables of typed GC references.
294-
295- Since the same mutable thread-local storage cells are shared by all core wasm
296- running under the same thread in the same component, the cells' contents must
297- be carefully coordinated in the same way as native code has to carefully
298- coordinate native ISA state (e.g., the [ FS or GS segment base address] ). In the
299- common case, thread-local storage is only ` context.set ` by the entry trampoline
300- invoked by [ ` canon_lift ` ] and then all transitively reachable core wasm code
301- (including from any ` callback ` ) assumes ` context.get ` returns the same value.
302- Thus, if any * non* -entry-trampoline code calls ` context.set ` , it is the
303- responsibility of * that code* to restore this default assumption before
304- allowing control flow to escape into the wild.
305-
306- For more information, see [ ` context.get ` ] in the AST explainer.
307-
308- ### Structured concurrency
249+ ### Subtasks and Supertasks
309250
310251As mentioned above, calling a component export creates a task to track the
311252state used to enforce Canonical ABI rules that apply to the callee (an example
@@ -375,6 +316,64 @@ For scenarios where one component wants to *non-cooperatively* put an upper
375316bound on execution of a call into another component, a separate "[ blast zone] "
376317feature is necessary in any case (due to iloops and traps).
377318
319+ ### Current Thread and Task
320+
321+ At any point in time while executing Core WebAssembly code or a [ canonical
322+ built-in] called by Core WebAssembly code, there is a well-defined ** current
323+ thread** whose containing task is the ** current task** . The "current thread" is
324+ modelled in the Canonical ABI's Python code by explicitly passing a [ ` Thread ` ]
325+ object as an argument to all function calls so that the semantic "current
326+ thread" is always the value of the ` thread ` parameter. Threads store their
327+ containing task so that the "current task" is always ` thread.task ` .
328+
329+ ### Thread-Local Storage
330+
331+ Each thread contains a distinct mutable ** thread-local storage** array. The
332+ current thread's thread-local storage can be read and written from core wasm
333+ code by calling the [ ` context.get ` ] and [ ` context.set ` ] built-ins.
334+
335+ The thread-local storage array's length is currently fixed to contain exactly
336+ 2 ` i32 ` s with the goal of allowing this array to be stored inline in whatever
337+ existing runtime data structure is already efficiently reachable from ambient
338+ compiled wasm code. Because module instantiation is declarative in the
339+ Component Model, the imported ` context.{get,set} ` built-ins can be inlined by
340+ the core wasm compiler as-if they were instructions, allowing the generated
341+ machine code to be a single load or store. This makes thread-local storage a
342+ natural place to store:
343+ 1 . a pointer to the linear-memory "shadow stack" pointer
344+ 2 . a pointer to a struct used by the runtime to implement the language's
345+ thread-local features
346+
347+ When threads are created explicitly by ` thread.new-indirect ` , the lifetime of
348+ the thread-local storage array ends when the function passed to
349+ ` thread.new-indirect ` returns and thus any linear-memory allocations associated
350+ with the thread-local storage array should be eagerly freed by guest code right
351+ before returning. Similarly, since each call to an export logically creates a
352+ fresh thread, thread-local allocations can be eagerly released when this
353+ implicit thread exits by returning from the exported function or, if the
354+ stackless async ABI is used, returning the "exit" code to the event loop. This
355+ non-reuse of thread-local storage between distinct export calls avoids what
356+ would otherwise be a likely source of TLS-related memory leaks.
357+
358+ When [ memory64] is integrated into the Component Model's Canonical ABI,
359+ ` context.{get,set} ` will be backwards-compatibly relaxed to allow ` i64 `
360+ pointers (overlaying the ` i32 ` values like hardware 32/64-bit registers). When
361+ [ wasm-gc] is integrated, these integral context values can serve as indices
362+ into guest-managed tables of typed GC references.
363+
364+ Since the same mutable thread-local storage cells are shared by all core wasm
365+ running under the same thread in the same component, the cells' contents must
366+ be carefully coordinated in the same way as native code has to carefully
367+ coordinate native ISA state (e.g., the [ FS or GS segment base address] ). In the
368+ common case, thread-local storage is only ` context.set ` by the entry trampoline
369+ invoked by [ ` canon_lift ` ] and then all transitively reachable core wasm code
370+ (including from any ` callback ` ) assumes ` context.get ` returns the same value.
371+ Thus, if any * non* -entry-trampoline code calls ` context.set ` , it is the
372+ responsibility of * that code* to restore this default assumption before
373+ allowing control flow to escape into the wild.
374+
375+ For more information, see [ ` context.get ` ] in the AST explainer.
376+
378377### Streams and Futures
379378
380379Streams and Futures have two "ends": a * readable end* and * writable end* . When
0 commit comments