1e06fbf70SSy Brand;;! component_model_async = true 2e06fbf70SSy Brand;;! component_model_threading = true 3e06fbf70SSy Brand 4e06fbf70SSy Brand;; Tests for basic functioning of all threading builtins with the implicit thread + one explicit thread 5e06fbf70SSy Brand;; Switches between threads using all of the different threading intrinsics. 6e06fbf70SSy Brand 7e06fbf70SSy Brand(component 8e06fbf70SSy Brand ;; Defines the table for the thread start function 9e06fbf70SSy Brand (core module $libc 10e06fbf70SSy Brand (table (export "__indirect_function_table") 1 funcref)) 11020727d0SAlex Crichton ;; Defines the thread start function and a function that calls thread.new-indirect 12e06fbf70SSy Brand (core module $m 13e06fbf70SSy Brand ;; Import the threading builtins and the table from libc 14020727d0SAlex Crichton (import "" "thread.new-indirect" (func $thread-new-indirect (param i32 i32) (result i32))) 15e06fbf70SSy Brand (import "" "thread.suspend" (func $thread-suspend (result i32))) 16*d2fbd2deSAlex Crichton (import "" "thread.yield-to-suspended" (func $thread-yield-to-suspended (param i32) (result i32))) 17*d2fbd2deSAlex Crichton (import "" "thread.suspend-to-suspended" (func $thread-suspend-to-suspended (param i32) (result i32))) 18e06fbf70SSy Brand (import "" "thread.yield" (func $thread-yield (result i32))) 19e06fbf70SSy Brand (import "" "thread.index" (func $thread-index (result i32))) 20*d2fbd2deSAlex Crichton (import "" "thread.unsuspend" (func $thread-unsuspend (param i32))) 21e06fbf70SSy Brand (import "libc" "__indirect_function_table" (table $indirect-function-table 1 funcref)) 22e06fbf70SSy Brand 23e06fbf70SSy Brand ;; A global that we will set from the spawned thread 24e06fbf70SSy Brand (global $g (mut i32) (i32.const 0)) 25e06fbf70SSy Brand (global $main-thread-index (mut i32) (i32.const 0)) 26e06fbf70SSy Brand 27e06fbf70SSy Brand ;; The thread entry point, which sets the global to incrementing values starting from the context value 28e06fbf70SSy Brand (func $thread-start (param i32) 29e06fbf70SSy Brand ;; Set the global to the context value 30e06fbf70SSy Brand (global.set $g (local.get 0)) 31e06fbf70SSy Brand ;; The main thread switched to us, so is no longer scheduled, so we explicitly schedule it 32*d2fbd2deSAlex Crichton (call $thread-unsuspend (global.get $main-thread-index)) 33e06fbf70SSy Brand ;; Yield back to the main thread (since that is the only other one) 34e06fbf70SSy Brand (drop (call $thread-yield) 35e06fbf70SSy Brand ;; Increment the global 36e06fbf70SSy Brand (global.set $g (i32.add (global.get $g) (i32.const 1))) 37e06fbf70SSy Brand ;; The main thread will have explicitly requested suspension, so yield to it directly 38*d2fbd2deSAlex Crichton (drop (call $thread-yield-to-suspended (global.get $main-thread-index))) 39e06fbf70SSy Brand ;; Increment the global again 40e06fbf70SSy Brand (global.set $g (i32.add (global.get $g) (i32.const 1))) 41e06fbf70SSy Brand ;; Reschedule the main thread so that it runs after we exit 42*d2fbd2deSAlex Crichton (call $thread-unsuspend (global.get $main-thread-index)))) 43e06fbf70SSy Brand (export "thread-start" (func $thread-start)) 44e06fbf70SSy Brand 45e06fbf70SSy Brand ;; Initialize the function table with our thread-start function; this will be 46020727d0SAlex Crichton ;; used by thread.new-indirect 47e06fbf70SSy Brand (elem (table $indirect-function-table) (i32.const 0) func $thread-start) 48e06fbf70SSy Brand 49e06fbf70SSy Brand ;; The main entry point, which spawns a new thread to run `thread-start`, passing 42 50e06fbf70SSy Brand ;; as the context value, and then yields to it 51e06fbf70SSy Brand (func (export "run") (result i32) 52e06fbf70SSy Brand ;; Store the main thread's index for the spawned thread to yield to 53e06fbf70SSy Brand (global.set $main-thread-index (call $thread-index)) 54e06fbf70SSy Brand ;; Create a new thread, which starts suspended, and switch to it 55e06fbf70SSy Brand (drop 56*d2fbd2deSAlex Crichton (call $thread-suspend-to-suspended 57e06fbf70SSy Brand (call $thread-new-indirect (i32.const 0) (i32.const 42)))) 58e06fbf70SSy Brand ;; After the thread yields back to us, check that the global was set to 42 59e06fbf70SSy Brand (if (i32.ne (global.get $g) (i32.const 42)) (then unreachable)) 60e06fbf70SSy Brand ;; Suspend ourselves, which will cause the spawned thread to run 61e06fbf70SSy Brand (drop (call $thread-suspend)) 62e06fbf70SSy Brand ;; The spawned thread will resume us after incrementing the global, so check that it is now 43 63e06fbf70SSy Brand (if (i32.ne (global.get $g) (i32.const 43)) (then unreachable)) 64e06fbf70SSy Brand ;; Suspend again, which will cause the spawned thread to run again 65e06fbf70SSy Brand (drop (call $thread-suspend)) 66e06fbf70SSy Brand ;; The spawned thread will reschedule us before it exits, so when we resume here the global should be 44 67e06fbf70SSy Brand (if (i32.ne (global.get $g) (i32.const 44)) (then unreachable)) 68e06fbf70SSy Brand ;; Return success 69e06fbf70SSy Brand (i32.const 42))) 70e06fbf70SSy Brand 71e06fbf70SSy Brand ;; Instantiate the libc module to get the table 72e06fbf70SSy Brand (core instance $libc (instantiate $libc)) 73020727d0SAlex Crichton ;; Get access to `thread.new-indirect` that uses the table from libc 74e06fbf70SSy Brand (core type $start-func-ty (func (param i32))) 75e06fbf70SSy Brand (alias core export $libc "__indirect_function_table" (core table $indirect-function-table)) 76e06fbf70SSy Brand 77e06fbf70SSy Brand (core func $thread-new-indirect 78020727d0SAlex Crichton (canon thread.new-indirect $start-func-ty (table $indirect-function-table))) 79e06fbf70SSy Brand (core func $thread-yield (canon thread.yield)) 80e06fbf70SSy Brand (core func $thread-index (canon thread.index)) 81*d2fbd2deSAlex Crichton (core func $thread-yield-to-suspended (canon thread.yield-to-suspended)) 82*d2fbd2deSAlex Crichton (core func $thread-unsuspend (canon thread.unsuspend)) 83*d2fbd2deSAlex Crichton (core func $thread-suspend-to-suspended (canon thread.suspend-to-suspended)) 84e06fbf70SSy Brand (core func $thread-suspend (canon thread.suspend)) 85e06fbf70SSy Brand 86e06fbf70SSy Brand ;; Instantiate the main module 87e06fbf70SSy Brand (core instance $i ( 88e06fbf70SSy Brand instantiate $m 89e06fbf70SSy Brand (with "" (instance 90020727d0SAlex Crichton (export "thread.new-indirect" (func $thread-new-indirect)) 91e06fbf70SSy Brand (export "thread.index" (func $thread-index)) 92*d2fbd2deSAlex Crichton (export "thread.yield-to-suspended" (func $thread-yield-to-suspended)) 93e06fbf70SSy Brand (export "thread.yield" (func $thread-yield)) 94*d2fbd2deSAlex Crichton (export "thread.suspend-to-suspended" (func $thread-suspend-to-suspended)) 95e06fbf70SSy Brand (export "thread.suspend" (func $thread-suspend)) 96*d2fbd2deSAlex Crichton (export "thread.unsuspend" (func $thread-unsuspend)))) 97e06fbf70SSy Brand (with "libc" (instance $libc)))) 98e06fbf70SSy Brand 99e06fbf70SSy Brand ;; Export the main entry point 1008992b99bSJoel Dice (func (export "run") async (result u32) (canon lift (core func $i "run")))) 101e06fbf70SSy Brand 102e06fbf70SSy Brand(assert_return (invoke "run") (u32.const 42)) 1034d129904SAlex Crichton 1044d129904SAlex Crichton;; Test that `thread.index` is exempt from may-leave checks 1054d129904SAlex Crichton(component 1064d129904SAlex Crichton (core func $thread.index (canon thread.index)) 1074d129904SAlex Crichton 1084d129904SAlex Crichton (core module $DM 1094d129904SAlex Crichton (import "" "thread.index" (func $thread.index (result i32))) 1104d129904SAlex Crichton 1114d129904SAlex Crichton (func (export "run")) 1124d129904SAlex Crichton (func (export "post-return") call $thread.index drop) 1134d129904SAlex Crichton ) 1144d129904SAlex Crichton (core instance $dm (instantiate $DM (with "" (instance 1154d129904SAlex Crichton (export "thread.index" (func $thread.index)) 1164d129904SAlex Crichton )))) 1174d129904SAlex Crichton (func (export "run") 1184d129904SAlex Crichton (canon lift (core func $dm "run") (post-return (func $dm "post-return")))) 1194d129904SAlex Crichton) 1204d129904SAlex Crichton 1214d129904SAlex Crichton(assert_return (invoke "run")) 122