1;;! reference_types = true 2;;! component_model_async = true 3 4(component definition $A 5 ;; A component with a single export that's just an infinitely looping 6 ;; subtask. Used to represent a pending subtask that has yet to resolve. 7 (component $a 8 (core module $m 9 (import "" "cancel" (func $cancel)) 10 (func (export "a") (result i32) i32.const 1) ;; CALLBACK_CODE_YIELD 11 (func (export "cb") (param i32 i32 i32) (result i32) 12 local.get 0 13 i32.const 6 ;; EVENT_TASK_CANCELLED 14 i32.eq 15 if (result i32) 16 call $cancel 17 i32.const 0 ;; CALLBACK_CODE_EXIT 18 else 19 i32.const 1 ;; CALLBACK_CODE_YIELD 20 end 21 22 ) 23 ) 24 (core func $cancel (canon task.cancel)) 25 (core instance $i (instantiate $m 26 (with "" (instance 27 (export "cancel" (func $cancel)) 28 )) 29 )) 30 (func (export "f") async 31 (canon lift (core func $i "a") async (callback (func $i "cb")))) 32 ) 33 34 (component $b 35 (import "f" (func $f async)) 36 (core module $m 37 (import "" "f" (func $f (result i32))) 38 (import "" "cancel" (func $cancel (param i32) (result i32))) 39 (import "" "drop" (func $drop (param i32))) 40 (global $subtask (mut i32) (i32.const 0)) 41 42 ;; This export starts a call to `$f` in the above component but doesn't 43 ;; await it or complete it. Instead this task exits. 44 (func (export "a") (param $cancel i32) 45 (local $ret i32) 46 47 ;; start the subtask 48 (local.set $ret (call $f)) 49 50 ;; verify it's in the `SUBTASK_STARTED` state 51 (i32.ne 52 (i32.and (local.get $ret) (i32.const 0xf)) 53 (i32.const 1)) ;; SUBTASK_STARTED 54 if unreachable end 55 56 ;; store the subtask id in a global. 57 (global.set $subtask 58 (i32.shr_u 59 (local.get $ret) 60 (i32.const 4))) 61 62 local.get $cancel 63 if call $call-cancel end 64 ) 65 66 (func $call-cancel 67 (i32.ne 68 (call $cancel (global.get $subtask)) 69 (i32.const 4)) ;; RETURN_CANCELLED 70 if unreachable end 71 ) 72 73 ;; This export tries to cancel/drop the subtask started by "a" above and 74 ;; this shouldn't cause any issues... 75 (func (export "b") (param $cancel i32) 76 local.get $cancel 77 if call $call-cancel end 78 (call $drop (global.get $subtask)) 79 ) 80 ) 81 (core func $f (canon lower (func $f) async)) 82 (core func $cancel (canon subtask.cancel)) 83 (core func $drop (canon subtask.drop)) 84 (core instance $i (instantiate $m 85 (with "" (instance 86 (export "f" (func $f)) 87 (export "cancel" (func $cancel)) 88 (export "drop" (func $drop)) 89 )) 90 )) 91 (func (export "a") async (param "cancel" bool) (canon lift (core func $i "a"))) 92 (func (export "b") async (param "cancel" bool) (canon lift (core func $i "b"))) 93 ) 94 95 (instance $a (instantiate $a)) 96 (instance $b (instantiate $b (with "f" (func $a "f")))) 97 (export "a" (func $b "a")) 98 (export "b" (func $b "b")) 99) 100 101;; start subtask in "a", cancel/drop it in "b" 102(component instance $A $A) 103(assert_return (invoke "a" (bool.const false))) 104(assert_return (invoke "b" (bool.const true))) 105 106;; start/cancel subtask in "a", drop it in "b" 107(component instance $A $A) 108(assert_return (invoke "a" (bool.const true))) 109(assert_return (invoke "b" (bool.const false))) 110