1;;! component_model_async = true
2;;! reference_types = true
3
4;; This test checks that an `EVENT_CANCELLED` can be delivered to a task that's
5;; in a `CALLBACK_CODE_YIELD` loop.
6(component
7  (component $a
8    (core module $m
9      (import "" "task.cancel" (func $task-cancel))
10      (import "" "thread.yield" (func $thread-yield (result i32)))
11
12      (func (export "f") (result i32)
13         ;; first, yield in a non-cancellable way a few times to give the caller
14         ;; a chance to queue up an `EVENT_CANCELLED`
15         (local $i i32)
16         (loop $loop
17           (i32.ne (i32.const 0 (; NOT_CANCELLED ;) (call $thread-yield)))
18           if unreachable end
19           (local.set $i (i32.add (i32.const 1) (local.get $i)))
20           (i32.ne (i32.const 10) (local.get $i))
21           br_if $loop
22         )
23
24         i32.const 1 ;; CALLBACK_CODE_YIELD
25      )
26
27      (func (export "f-callback") (param i32 i32 i32) (result i32)
28         (i32.eq (i32.const 6 (; EVENT_CANCELLED ;)) (local.get 0))
29         (if (result i32)
30           (then
31             call $task-cancel
32             i32.const 0 ;; CALLBACK_CODE_EXIT
33           )
34           (else
35             i32.const 1 ;; CALLBACK_CODE_YIELD
36           )
37         )
38      )
39    )
40
41    (core func $task-cancel (canon task.cancel))
42    (core func $thread-yield (canon thread.yield))
43
44    (core instance $i (instantiate $m
45      (with "" (instance
46        (export "task.cancel" (func $task-cancel))
47        (export "thread.yield" (func $thread-yield))
48      ))
49    ))
50
51    (func (export "f") async (canon lift (core func $i "f") async (callback (func $i "f-callback"))))
52  )
53  (instance $a (instantiate $a))
54
55  (component $b
56    (import "a" (instance $a
57      (export "f" (func async))
58    ))
59
60    (core module $m
61      (import "" "f" (func $f (result i32)))
62      (import "" "subtask.cancel" (func $subtask-cancel (param i32) (result i32)))
63
64      (func (export "f")
65         (local $status i32)
66         (local $subtask i32)
67
68         (local.set $status (call $f))
69         (local.set $subtask (i32.shr_u (local.get $status) (i32.const 4)))
70         (local.set $status (i32.and (i32.const 0xF) (local.get $status)))
71         (i32.ne (i32.const 1 (; STATUS_STARTED ;)) (local.get $status))
72         if unreachable end
73         (i32.ne (i32.const 4 (; STATUS_RETURN_CANCELLED ;)) (call $subtask-cancel (local.get $subtask)))
74         if unreachable end
75      )
76    )
77
78    (core func $f (canon lower (func $a "f") async))
79    (core func $subtask-cancel (canon subtask.cancel))
80
81    (core instance $i (instantiate $m
82      (with "" (instance
83        (export "f" (func $f))
84        (export "subtask.cancel" (func $subtask-cancel))
85      ))
86    ))
87
88    (func (export "f") async (canon lift (core func $i "f")))
89  )
90  (instance $b (instantiate $b
91     (with "a" (instance $a))
92  ))
93
94  (func (export "f") (alias export $b "f"))
95)
96
97(assert_return (invoke "f"))
98