1e06fbf70SSy Brand;;! component_model_async = true 2e06fbf70SSy Brand;;! component_model_async_stackful = true 3e06fbf70SSy Brand;;! component_model_async_builtins = true 4e06fbf70SSy Brand;;! component_model_threading = true 5e06fbf70SSy Brand;;! reference_types = true 6e06fbf70SSy Brand 7e06fbf70SSy Brand;; Tests that cancellation works with the async threading intrinsics. 8e06fbf70SSy Brand;; Consists of two components, C and D. C implements functions that mix cancellable and uncancellable yields and suspensions. 9e06fbf70SSy Brand;; D calls these functions and cancels the resulting subtasks, ensuring that cancellation is only seen when expected. 10e06fbf70SSy Brand 11e06fbf70SSy Brand;; -- Component C -- 12e06fbf70SSy Brand 13e06fbf70SSy Brand;; `run-yield`: Yields twice, first with an uncancellable yield, then with a cancellable yield. 14e06fbf70SSy Brand;; The caller cancels the subtask during the first yield, and ensures that the cancellation only takes effect 15e06fbf70SSy Brand;; on the second yield. 16e06fbf70SSy Brand 17*d2fbd2deSAlex Crichton;; `run-yield-to-suspended`: Yields twice to a spawned thread, first with an uncancellable yield, then with a cancellable yield. 18e06fbf70SSy Brand;; A complication is that we can't guarantee that if the spawned thread yields, the supertask will be scheduled to 19e06fbf70SSy Brand;; cancel the subtask before the subtask's implicit thread is rescheduled. To handle this, the subtask's implicit 20e06fbf70SSy Brand;; thread first waits on a future to be written by the supertask, then yields to the spawned thread. 21e06fbf70SSy Brand 22e06fbf70SSy Brand;; `run-suspend`: More complex, because executing an uncancellable suspension requires another 23e06fbf70SSy Brand;; thread in the same subtask to explicitly wake it up. This is done by the subtask spawning a new thread that 24e06fbf70SSy Brand;; waits on a future to be written by the supertask, and then resumes the main thread once that happens. 25e06fbf70SSy Brand;; After setting up this thread, `run-suspend` performs an uncancellable suspend, then a cancellable suspend. 26e06fbf70SSy Brand;; The caller cancels the subtask during the first suspend, writes to the future to make the spawned thread 27e06fbf70SSy Brand;; resume the implicit thread, and ensures that the cancellation only takes effect on the second suspend. 28e06fbf70SSy Brand 29*d2fbd2deSAlex Crichton;; `run-suspend-to-suspended`: Similar to `run-suspend`, but uses `thread.suspend-to-suspended` instead of `thread.suspend`. 30e06fbf70SSy Brand 31e06fbf70SSy Brand;; -- Component D -- 32e06fbf70SSy Brand 33e06fbf70SSy Brand;; `run-test`: Calls one of the functions in C based on a test id, cancels the resulting subtask, and ensures that 34e06fbf70SSy Brand;; cancellation is only seen when expected. 35e06fbf70SSy Brand 36e06fbf70SSy Brand;; `run`: Calls `run-test` for each of the functions in C. 37e06fbf70SSy Brand 38e06fbf70SSy Brand(component 39e06fbf70SSy Brand (component $C 40e06fbf70SSy Brand (type $FT (future)) 41e06fbf70SSy Brand (core module $Memory (memory (export "mem") 1)) 42e06fbf70SSy Brand (core instance $memory (instantiate $Memory)) 43e06fbf70SSy Brand ;; Defines the table for the thread start functions, of which there are two 44e06fbf70SSy Brand (core module $libc 45e06fbf70SSy Brand (table (export "__indirect_function_table") 2 funcref)) 46e06fbf70SSy Brand (core module $CM 47e06fbf70SSy Brand (import "" "mem" (memory 1)) 48e06fbf70SSy Brand (import "" "task.cancel" (func $task-cancel)) 49020727d0SAlex Crichton (import "" "thread.new-indirect" (func $thread-new-indirect (param i32 i32) (result i32))) 50e06fbf70SSy Brand (import "" "thread.suspend" (func $thread-suspend (result i32))) 51e06fbf70SSy Brand (import "" "thread.suspend-cancellable" (func $thread-suspend-cancellable (result i32))) 52*d2fbd2deSAlex Crichton (import "" "thread.yield-to-suspended" (func $thread-yield-to-suspended (param i32) (result i32))) 53*d2fbd2deSAlex Crichton (import "" "thread.yield-to-suspended-cancellable" (func $thread-yield-to-suspended-cancellable (param i32) (result i32))) 54*d2fbd2deSAlex Crichton (import "" "thread.suspend-to-suspended" (func $thread-suspend-to-suspended (param i32) (result i32))) 55*d2fbd2deSAlex Crichton (import "" "thread.suspend-to-suspended-cancellable" (func $thread-suspend-to-suspended-cancellable (param i32) (result i32))) 56e06fbf70SSy Brand (import "" "thread.yield" (func $thread-yield (result i32))) 57e06fbf70SSy Brand (import "" "thread.yield-cancellable" (func $thread-yield-cancellable (result i32))) 58e06fbf70SSy Brand (import "" "thread.index" (func $thread-index (result i32))) 59*d2fbd2deSAlex Crichton (import "" "thread.unsuspend" (func $thread-unsuspend (param i32))) 60e06fbf70SSy Brand (import "" "future.read" (func $future.read (param i32 i32) (result i32))) 61e06fbf70SSy Brand (import "" "waitable.join" (func $waitable.join (param i32 i32))) 62e06fbf70SSy Brand (import "" "waitable-set.new" (func $waitable-set.new (result i32))) 63e06fbf70SSy Brand (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) 64e06fbf70SSy Brand (import "libc" "__indirect_function_table" (table $indirect-function-table 2 funcref)) 65e06fbf70SSy Brand 66e06fbf70SSy Brand ;; Indices into the function table for the thread start functions 67e06fbf70SSy Brand (global $wake-from-suspend-ftbl-idx i32 (i32.const 0)) 68e06fbf70SSy Brand (global $just-yield-ftbl-idx i32 (i32.const 1)) 69e06fbf70SSy Brand 70e06fbf70SSy Brand (func (export "run-yield") 71e06fbf70SSy Brand ;; Yield back to the caller, who will attempt to cancel us, but we won't see it 72e06fbf70SSy Brand ;; because we're using an uncancellable yield 73e06fbf70SSy Brand (if (i32.ne (call $thread-yield) (i32.const 0)) (then unreachable)) 74e06fbf70SSy Brand ;; Yield back to the caller again. This time, we should receive the cancellation immediately. 75e06fbf70SSy Brand (if (i32.ne (call $thread-yield-cancellable) (i32.const 1)) (then unreachable)) 76e06fbf70SSy Brand (call $task-cancel) 77e06fbf70SSy Brand ) 78e06fbf70SSy Brand 79e06fbf70SSy Brand (func $wait-for-future-write (param i32) 80e06fbf70SSy Brand (local $ret i32) 81e06fbf70SSy Brand ;; Perform a future.read, which will block, waiting for the supertask to write 82e06fbf70SSy Brand (local.set $ret (call $future.read (local.get 0) (i32.const 0xba5eba11))) 83e06fbf70SSy Brand (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) 84e06fbf70SSy Brand (then unreachable)) 85e06fbf70SSy Brand ) 86e06fbf70SSy Brand 87e06fbf70SSy Brand (func $wake-from-suspend (param i32) 88e06fbf70SSy Brand ;; Extract the thread index and future to wait on from the argument structure 89e06fbf70SSy Brand (local $thread-index i32) (local $future i32) 90e06fbf70SSy Brand (local.set $thread-index (i32.load offset=0 (local.get 0))) 91e06fbf70SSy Brand (local.set $future (i32.load offset=4 (local.get 0))) 92e06fbf70SSy Brand 93e06fbf70SSy Brand ;; Wait for the supertask to signal us to wake up suspended thread. 94e06fbf70SSy Brand (call $wait-for-future-write (local.get $future)) 95e06fbf70SSy Brand ;; Resume the main thread, which is suspended in an uncancellable suspend 96*d2fbd2deSAlex Crichton (call $thread-unsuspend (local.get $thread-index)) 97e06fbf70SSy Brand ) 98e06fbf70SSy Brand 99e06fbf70SSy Brand (func $just-yield (param $explicit-thread-idx i32) 100e06fbf70SSy Brand ;; Yield nondeterministically, either back to the supertask, who will then wait on cancellation to be acknowledged, 101e06fbf70SSy Brand ;; or to the implicit thread, who will acknowledge the cancellation. 102e06fbf70SSy Brand (if (i32.ne (call $thread-yield) (i32.const 0)) (then unreachable)) 103e06fbf70SSy Brand ) 104e06fbf70SSy Brand 105020727d0SAlex Crichton ;; Initialize the function table that will be used by thread.new-indirect 106e06fbf70SSy Brand (elem (table $indirect-function-table) (i32.const 0 (; wake-from-suspend-ftbl-idx ;)) func $wake-from-suspend) 107e06fbf70SSy Brand (elem (table $indirect-function-table) (i32.const 1 (; just-yield-ftbl-idx ;)) func $just-yield) 108e06fbf70SSy Brand 109*d2fbd2deSAlex Crichton (func (export "run-yield-to-suspended") (param $futr i32) 110e06fbf70SSy Brand (local $thread-index i32) 111e06fbf70SSy Brand ;; Spawn a new thread that will wake us up from our uncancellable suspend; we'll switch to it next 112e06fbf70SSy Brand (local.set $thread-index 113e06fbf70SSy Brand (call $thread-new-indirect (global.get $just-yield-ftbl-idx) (call $thread-index))) 114e06fbf70SSy Brand 115e06fbf70SSy Brand ;; We can't guarantee that the supertask will be scheduled to cancel us before we're rescheduled, so we first 116e06fbf70SSy Brand ;; wait on the future to be written, then yield to the spawned thread. This means that cancellation will be 117e06fbf70SSy Brand ;; sent while we're waiting on the future rather than at the yield point, but the cancel will still be pending 118e06fbf70SSy Brand ;; when we reach the yield point, so it should still be ignored by the uncancellable yield and only take effect 119e06fbf70SSy Brand ;; when we reach the second, cancellable yield. 120e06fbf70SSy Brand (call $wait-for-future-write (local.get $futr)) 121e06fbf70SSy Brand 122e06fbf70SSy Brand ;; Yield to the spawned thread uncancellably. We should eventually be rescheduled without being notified 123e06fbf70SSy Brand ;; of the pending cancellation. 124*d2fbd2deSAlex Crichton (if (i32.ne (call $thread-yield-to-suspended (local.get $thread-index)) (i32.const 0)) (then unreachable)) 125e06fbf70SSy Brand ;; Yield to the spawned thread again. This time we should see the cancellation immediately. 126*d2fbd2deSAlex Crichton (if (i32.ne (call $thread-yield-to-suspended-cancellable (local.get $thread-index)) (i32.const 1)) (then unreachable)) 127e06fbf70SSy Brand (call $task-cancel) 128e06fbf70SSy Brand ) 129e06fbf70SSy Brand 130e06fbf70SSy Brand (func (export "run-suspend") (param $futr i32) 131e06fbf70SSy Brand ;; Set up the arguments for the wake-for-suspend thread start function. 132e06fbf70SSy Brand ;; It expects a pointer to a structure containing the thread index to resume 133e06fbf70SSy Brand ;; and the future to wait on before resuming it. 134e06fbf70SSy Brand (local $wake-from-suspend-argp i32) 135e06fbf70SSy Brand (local.set $wake-from-suspend-argp (i32.const 4)) 136e06fbf70SSy Brand (i32.store offset=0 (local.get $wake-from-suspend-argp) (call $thread-index)) 137e06fbf70SSy Brand (i32.store offset=4 (local.get $wake-from-suspend-argp) (local.get $futr)) 138e06fbf70SSy Brand 139e06fbf70SSy Brand ;; Spawn a new thread that will wake us up from our uncancellable suspend and schedule 140e06fbf70SSy Brand ;; it to resume after we suspend. 141*d2fbd2deSAlex Crichton (call $thread-unsuspend 142e06fbf70SSy Brand (call $thread-new-indirect (global.get $wake-from-suspend-ftbl-idx) (local.get $wake-from-suspend-argp))) 143e06fbf70SSy Brand 144e06fbf70SSy Brand ;; Request suspension. We will not be woken up by cancellation, because this is an uncancellable 145e06fbf70SSy Brand ;; suspend. We will be woken up by the other thread we spawned above, which will be resumed after 146e06fbf70SSy Brand ;; the supertask cancels our subtask. 147e06fbf70SSy Brand (if (i32.ne (call $thread-suspend) (i32.const 0)) (then unreachable)) 148e06fbf70SSy Brand ;; Request suspension again. This time we should see the cancellation immediately. 149e06fbf70SSy Brand (if (i32.ne (call $thread-suspend-cancellable) (i32.const 1)) (then unreachable)) 150e06fbf70SSy Brand (call $task-cancel) 151e06fbf70SSy Brand ) 152e06fbf70SSy Brand 153*d2fbd2deSAlex Crichton (func (export "run-suspend-to-suspended") (param $futr i32) 154e06fbf70SSy Brand (local $thread-index i32) 155e06fbf70SSy Brand ;; Set up the arguments for the wake-for-suspend thread start function. 156e06fbf70SSy Brand ;; It expects a pointer to a structure containing the thread index to resume 157e06fbf70SSy Brand ;; and the future to wait on before resuming it. 158e06fbf70SSy Brand (local $wake-from-suspend-argp i32) 159e06fbf70SSy Brand (local.set $wake-from-suspend-argp (i32.const 4)) 160e06fbf70SSy Brand (i32.store offset=0 (local.get $wake-from-suspend-argp) (call $thread-index)) 161e06fbf70SSy Brand (i32.store offset=4 (local.get $wake-from-suspend-argp) (local.get $futr)) 162e06fbf70SSy Brand 163e06fbf70SSy Brand ;; Spawn a new thread that will wake us up from our uncancellable suspend; we'll switch to it next 164e06fbf70SSy Brand (local.set $thread-index 165e06fbf70SSy Brand (call $thread-new-indirect (global.get $wake-from-suspend-ftbl-idx) (local.get $wake-from-suspend-argp))) 166e06fbf70SSy Brand 167e06fbf70SSy Brand ;; Request suspension by switching to the spawned thread. 168e06fbf70SSy Brand ;; We will not be woken up by cancellation, because this is an uncancellable suspend. 169e06fbf70SSy Brand ;; We will be woken up by the other thread we spawned above, which will be resumed after 170e06fbf70SSy Brand ;; the supertask cancels our subtask. 171*d2fbd2deSAlex Crichton (if (i32.ne (call $thread-suspend-to-suspended (local.get $thread-index)) (i32.const 0)) (then unreachable)) 172e06fbf70SSy Brand ;; Request suspension again. This time we should see the cancellation immediately. 173*d2fbd2deSAlex Crichton (if (i32.ne (call $thread-suspend-to-suspended-cancellable (local.get $thread-index)) (i32.const 1)) (then unreachable)) 174e06fbf70SSy Brand (call $task-cancel) 175e06fbf70SSy Brand ) 176e06fbf70SSy Brand ) 177e06fbf70SSy Brand 178e06fbf70SSy Brand ;; Instantiate the libc module to get the table 179e06fbf70SSy Brand (core instance $libc (instantiate $libc)) 180020727d0SAlex Crichton ;; Get access to `thread.new-indirect` that uses the table from libc 181e06fbf70SSy Brand (core type $start-func-ty (func (param i32))) 182e06fbf70SSy Brand (alias core export $libc "__indirect_function_table" (core table $indirect-function-table)) 183e06fbf70SSy Brand 184e06fbf70SSy Brand (core func $task-cancel (canon task.cancel)) 185e06fbf70SSy Brand (core func $thread-new-indirect 186020727d0SAlex Crichton (canon thread.new-indirect $start-func-ty (table $indirect-function-table))) 187e06fbf70SSy Brand (core func $thread-yield (canon thread.yield)) 188e06fbf70SSy Brand (core func $thread-yield-cancellable (canon thread.yield cancellable)) 189e06fbf70SSy Brand (core func $thread-index (canon thread.index)) 190*d2fbd2deSAlex Crichton (core func $thread-yield-to-suspended (canon thread.yield-to-suspended)) 191*d2fbd2deSAlex Crichton (core func $thread-yield-to-suspended-cancellable (canon thread.yield-to-suspended cancellable)) 192*d2fbd2deSAlex Crichton (core func $thread-unsuspend (canon thread.unsuspend)) 193*d2fbd2deSAlex Crichton (core func $thread-suspend-to-suspended (canon thread.suspend-to-suspended)) 194*d2fbd2deSAlex Crichton (core func $thread-suspend-to-suspended-cancellable (canon thread.suspend-to-suspended cancellable)) 195e06fbf70SSy Brand (core func $thread-suspend (canon thread.suspend)) 196e06fbf70SSy Brand (core func $thread-suspend-cancellable (canon thread.suspend cancellable)) 197e06fbf70SSy Brand (core func $future.read (canon future.read $FT (memory $memory "mem"))) 198e06fbf70SSy Brand (core func $waitable-set.new (canon waitable-set.new)) 199e06fbf70SSy Brand (core func $waitable.join (canon waitable.join)) 200e06fbf70SSy Brand (core func $waitable-set.wait (canon waitable-set.wait (memory $memory "mem"))) 201e06fbf70SSy Brand 202e06fbf70SSy Brand ;; Instantiate the main module 203e06fbf70SSy Brand (core instance $cm ( 204e06fbf70SSy Brand instantiate $CM 205e06fbf70SSy Brand (with "" (instance 206e06fbf70SSy Brand (export "mem" (memory $memory "mem")) 207e06fbf70SSy Brand (export "task.cancel" (func $task-cancel)) 208020727d0SAlex Crichton (export "thread.new-indirect" (func $thread-new-indirect)) 209e06fbf70SSy Brand (export "thread.index" (func $thread-index)) 210*d2fbd2deSAlex Crichton (export "thread.yield-to-suspended" (func $thread-yield-to-suspended)) 211*d2fbd2deSAlex Crichton (export "thread.yield-to-suspended-cancellable" (func $thread-yield-to-suspended-cancellable)) 212e06fbf70SSy Brand (export "thread.yield" (func $thread-yield)) 213e06fbf70SSy Brand (export "thread.yield-cancellable" (func $thread-yield-cancellable)) 214*d2fbd2deSAlex Crichton (export "thread.suspend-to-suspended" (func $thread-suspend-to-suspended)) 215*d2fbd2deSAlex Crichton (export "thread.suspend-to-suspended-cancellable" (func $thread-suspend-to-suspended-cancellable)) 216e06fbf70SSy Brand (export "thread.suspend" (func $thread-suspend)) 217e06fbf70SSy Brand (export "thread.suspend-cancellable" (func $thread-suspend-cancellable)) 218*d2fbd2deSAlex Crichton (export "thread.unsuspend" (func $thread-unsuspend)) 219e06fbf70SSy Brand (export "future.read" (func $future.read)) 220e06fbf70SSy Brand (export "waitable.join" (func $waitable.join)) 221e06fbf70SSy Brand (export "waitable-set.wait" (func $waitable-set.wait)) 222e06fbf70SSy Brand (export "waitable-set.new" (func $waitable-set.new)))) 223e06fbf70SSy Brand (with "libc" (instance $libc)))) 224e06fbf70SSy Brand 2258992b99bSJoel Dice (func (export "run-yield") async (result u32) (canon lift (core func $cm "run-yield") async)) 226*d2fbd2deSAlex Crichton (func (export "run-yield-to-suspended") async (param "fut" $FT) (result u32) (canon lift (core func $cm "run-yield-to-suspended") async)) 2278992b99bSJoel Dice (func (export "run-suspend") async (param "fut" $FT) (result u32) (canon lift (core func $cm "run-suspend") async)) 228*d2fbd2deSAlex Crichton (func (export "run-suspend-to-suspended") async (param "fut" $FT) (result u32) (canon lift (core func $cm "run-suspend-to-suspended") async)) 229e06fbf70SSy Brand ) 230e06fbf70SSy Brand 231e06fbf70SSy Brand (component $D 232e06fbf70SSy Brand (type $FT (future)) 2338992b99bSJoel Dice (import "run-yield" (func $run-yield async (result u32))) 234*d2fbd2deSAlex Crichton (import "run-yield-to-suspended" (func $run-yield-to-suspended async (param "fut" $FT) (result u32))) 2358992b99bSJoel Dice (import "run-suspend" (func $run-suspend async (param "fut" $FT) (result u32))) 236*d2fbd2deSAlex Crichton (import "run-suspend-to-suspended" (func $run-suspend-to-suspended async (param "fut" $FT) (result u32))) 237e06fbf70SSy Brand 238e06fbf70SSy Brand (core module $Memory (memory (export "mem") 1)) 239e06fbf70SSy Brand (core instance $memory (instantiate $Memory)) 240e06fbf70SSy Brand (core module $DM 241e06fbf70SSy Brand (import "" "mem" (memory 1)) 242e06fbf70SSy Brand (import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32))) 243e06fbf70SSy Brand (import "" "run-yield" (func $run-yield (param i32) (result i32))) 244*d2fbd2deSAlex Crichton (import "" "run-yield-to-suspended" (func $run-yield-to-suspended (param i32 i32) (result i32))) 245e06fbf70SSy Brand (import "" "run-suspend" (func $run-suspend (param i32 i32) (result i32))) 246*d2fbd2deSAlex Crichton (import "" "run-suspend-to-suspended" (func $run-suspend-to-suspended (param i32 i32) (result i32))) 247e06fbf70SSy Brand (import "" "waitable.join" (func $waitable.join (param i32 i32))) 248e06fbf70SSy Brand (import "" "waitable-set.new" (func $waitable-set.new (result i32))) 249e06fbf70SSy Brand (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) 250e06fbf70SSy Brand (import "" "future.new" (func $future.new (result i64))) 251e06fbf70SSy Brand (import "" "future.write" (func $future.write (param i32 i32) (result i32))) 252e06fbf70SSy Brand (import "" "thread.yield" (func $thread-yield (result i32))) 253e06fbf70SSy Brand 254e06fbf70SSy Brand (func $run-test (param $test-id i32) (result i32) 255e06fbf70SSy Brand (local $ret i32) (local $subtask i32) 256e06fbf70SSy Brand (local $ws i32) (local $event_code i32) 257e06fbf70SSy Brand (local $run-retp i32) (local $wait-retp i32) 258e06fbf70SSy Brand (local $ret64 i64) (local $futr i32) (local $futw i32) 259e06fbf70SSy Brand 260*d2fbd2deSAlex Crichton ;; Set up return value storage for run-suspend/suspend-to-suspended and waitable-set.wait 261e06fbf70SSy Brand (local.set $run-retp (i32.const 4)) 262e06fbf70SSy Brand (local.set $wait-retp (i32.const 8)) 263e06fbf70SSy Brand (i32.store (local.get $run-retp) (i32.const 0xbad0bad0)) 264e06fbf70SSy Brand (i32.store (local.get $wait-retp) (i32.const 0xbad0bad0)) 265e06fbf70SSy Brand 266e06fbf70SSy Brand ;; Create a future that the subtask may wait on 267e06fbf70SSy Brand (local.set $ret64 (call $future.new)) 268e06fbf70SSy Brand (local.set $futr (i32.wrap_i64 (local.get $ret64))) 269e06fbf70SSy Brand (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) 270e06fbf70SSy Brand 271*d2fbd2deSAlex Crichton ;; Calling run-suspend/suspend-to-suspended will start the thread, which will suspend. 272e06fbf70SSy Brand ;; This is basically a switch statement: 273e06fbf70SSy Brand ;; 0: run-yield 274*d2fbd2deSAlex Crichton ;; 1: run-yield-to-suspended 275e06fbf70SSy Brand ;; 2: run-suspend 276*d2fbd2deSAlex Crichton ;; 3: run-suspend-to-suspended 277e06fbf70SSy Brand (if (i32.eq (local.get $test-id) (i32.const 0)) 278e06fbf70SSy Brand (then (local.set $ret (call $run-yield (local.get $run-retp)))) 279e06fbf70SSy Brand (else (if (i32.eq (local.get $test-id) (i32.const 1)) 280*d2fbd2deSAlex Crichton (then (local.set $ret (call $run-yield-to-suspended (local.get $futr) (local.get $run-retp)))) 281e06fbf70SSy Brand (else (if (i32.eq (local.get $test-id) (i32.const 2)) 282e06fbf70SSy Brand (then (local.set $ret (call $run-suspend (local.get $futr) (local.get $run-retp)))) 283e06fbf70SSy Brand (else (if (i32.eq (local.get $test-id) (i32.const 3)) 284*d2fbd2deSAlex Crichton (then (local.set $ret (call $run-suspend-to-suspended (local.get $futr) (local.get $run-retp)))) 285e06fbf70SSy Brand (else unreachable)))))))) 286e06fbf70SSy Brand 287e06fbf70SSy Brand ;; Ensure that the thread started 288e06fbf70SSy Brand (if (i32.ne (i32.and (local.get $ret) (i32.const 0xF)) (i32.const 1 (; STARTED ;))) 289e06fbf70SSy Brand (then unreachable)) 290e06fbf70SSy Brand ;; Extract the subtask index 291e06fbf70SSy Brand (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) 292e06fbf70SSy Brand ;; Cancel the subtask, which should block, because the initial suspend/yield is uncancellable 293e06fbf70SSy Brand (local.set $ret (call $subtask.cancel (local.get $subtask))) 294e06fbf70SSy Brand ;; Ensure the cancellation blocked 295e06fbf70SSy Brand (if (i32.ne (local.get $ret) (i32.const -1 (; BLOCKED ;))) 296e06fbf70SSy Brand (then unreachable)) 297e06fbf70SSy Brand 298e06fbf70SSy Brand ;; If we're not testing run-yield, the subtask is expecting a write to our future, so write to it 299e06fbf70SSy Brand (if (i32.ne (local.get $test-id) (i32.const 0)) 300e06fbf70SSy Brand (then 301e06fbf70SSy Brand (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) 302e06fbf70SSy Brand ;; The write should succeed 303e06fbf70SSy Brand (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) 304e06fbf70SSy Brand (then unreachable)))) 305e06fbf70SSy Brand 306e06fbf70SSy Brand ;; Wait on the subtask, which will eventually progress to a cancellable yield/suspend and acknowledge the cancellation 307e06fbf70SSy Brand (local.set $ws (call $waitable-set.new)) 308e06fbf70SSy Brand (call $waitable.join (local.get $subtask) (local.get $ws)) 309e06fbf70SSy Brand (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $wait-retp))) 310e06fbf70SSy Brand ;; Ensure we got the subtask event 311e06fbf70SSy Brand (if (i32.ne (local.get $event_code) (i32.const 1 (; SUBTASK ;))) 312e06fbf70SSy Brand (then unreachable)) 313e06fbf70SSy Brand ;; Ensure the subtask index matches 314e06fbf70SSy Brand (if (i32.ne (local.get $subtask) (i32.load (local.get $wait-retp))) 315e06fbf70SSy Brand (then unreachable)) 316e06fbf70SSy Brand ;; Ensure the subtask was cancelled before it returned 317e06fbf70SSy Brand (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED=4 | (0<<4) ;)) 318e06fbf70SSy Brand (i32.load offset=4 (local.get $wait-retp))) 319e06fbf70SSy Brand (then unreachable)) 320e06fbf70SSy Brand 321e06fbf70SSy Brand ;; Return success 322e06fbf70SSy Brand (i32.const 42) 323e06fbf70SSy Brand ) 324e06fbf70SSy Brand 325e06fbf70SSy Brand (func $run (export "run") (result i32) 326e06fbf70SSy Brand ;; test-id 0: run-yield 327e06fbf70SSy Brand (if (i32.ne (call $run-test (i32.const 0)) (i32.const 42)) 328e06fbf70SSy Brand (then unreachable)) 329e06fbf70SSy Brand 330*d2fbd2deSAlex Crichton ;; test-id 1: run-yield-to-suspended 331e06fbf70SSy Brand (if (i32.ne (call $run-test (i32.const 1)) (i32.const 42)) 332e06fbf70SSy Brand (then unreachable)) 333e06fbf70SSy Brand 334e06fbf70SSy Brand ;; test-id 2: run-suspend 335e06fbf70SSy Brand (if (i32.ne (call $run-test (i32.const 2)) (i32.const 42)) 336e06fbf70SSy Brand (then unreachable)) 337e06fbf70SSy Brand 338*d2fbd2deSAlex Crichton ;; test-id 3: run-suspend-to-suspended 339e06fbf70SSy Brand (if (i32.ne (call $run-test (i32.const 3)) (i32.const 42)) 340e06fbf70SSy Brand (then unreachable)) 341e06fbf70SSy Brand 342e06fbf70SSy Brand ;; Return success 343e06fbf70SSy Brand (i32.const 42) 344e06fbf70SSy Brand ) 345e06fbf70SSy Brand ) 346e06fbf70SSy Brand 347e06fbf70SSy Brand (core func $waitable-set.new (canon waitable-set.new)) 348e06fbf70SSy Brand (core func $waitable-set.wait (canon waitable-set.wait (memory $memory "mem"))) 349e06fbf70SSy Brand (core func $waitable.join (canon waitable.join)) 350e06fbf70SSy Brand (core func $subtask.cancel (canon subtask.cancel async)) 351e06fbf70SSy Brand (core func $future.new (canon future.new $FT)) 352e06fbf70SSy Brand (core func $future.write (canon future.write $FT (memory $memory "mem"))) 353e06fbf70SSy Brand (core func $thread.yield (canon thread.yield)) 354e06fbf70SSy Brand (canon lower (func $run-yield) async (memory $memory "mem") (core func $run-yield')) 355e06fbf70SSy Brand (canon lower (func $run-suspend) async (memory $memory "mem") (core func $run-suspend')) 356*d2fbd2deSAlex Crichton (canon lower (func $run-suspend-to-suspended) async (memory $memory "mem") (core func $run-suspend-to-suspended')) 357*d2fbd2deSAlex Crichton (canon lower (func $run-yield-to-suspended) async (memory $memory "mem") (core func $run-yield-to-suspended')) 358e06fbf70SSy Brand (core instance $dm (instantiate $DM (with "" (instance 359e06fbf70SSy Brand (export "mem" (memory $memory "mem")) 360e06fbf70SSy Brand (export "run-yield" (func $run-yield')) 361e06fbf70SSy Brand (export "run-suspend" (func $run-suspend')) 362*d2fbd2deSAlex Crichton (export "run-suspend-to-suspended" (func $run-suspend-to-suspended')) 363*d2fbd2deSAlex Crichton (export "run-yield-to-suspended" (func $run-yield-to-suspended')) 364e06fbf70SSy Brand (export "waitable.join" (func $waitable.join)) 365e06fbf70SSy Brand (export "waitable-set.new" (func $waitable-set.new)) 366e06fbf70SSy Brand (export "waitable-set.wait" (func $waitable-set.wait)) 367e06fbf70SSy Brand (export "subtask.cancel" (func $subtask.cancel)) 368e06fbf70SSy Brand (export "future.new" (func $future.new)) 369e06fbf70SSy Brand (export "future.write" (func $future.write)) 370e06fbf70SSy Brand (export "thread.yield" (func $thread.yield)) 371e06fbf70SSy Brand )))) 3728992b99bSJoel Dice (func (export "run") async (result u32) (canon lift (core func $dm "run"))) 373e06fbf70SSy Brand ) 374e06fbf70SSy Brand 375e06fbf70SSy Brand (instance $c (instantiate $C)) 376e06fbf70SSy Brand (instance $d (instantiate $D 377e06fbf70SSy Brand (with "run-yield" (func $c "run-yield")) 378*d2fbd2deSAlex Crichton (with "run-yield-to-suspended" (func $c "run-yield-to-suspended")) 379e06fbf70SSy Brand (with "run-suspend" (func $c "run-suspend")) 380*d2fbd2deSAlex Crichton (with "run-suspend-to-suspended" (func $c "run-suspend-to-suspended")) 381e06fbf70SSy Brand )) 382e06fbf70SSy Brand (func (export "run") (alias export $d "run")) 383e06fbf70SSy Brand) 384e06fbf70SSy Brand 385e06fbf70SSy Brand(assert_return (invoke "run") (u32.const 42)) 386