1;;! component_model_async = true
2;;! reference_types = true
3;;! gc_types = true
4;;! multi_memory = true
5
6;; - Component B asks component A to enable backpressure
7;; - Component B makes an async call to component A
8;; - Component B asserts this subtask is in the "STARTING" state
9;; - Component B adds the subtask to a waitable set and calls waitable-set.wait
10;;
11;; This leaves both tasks in a deadlock situation, which, as of this writing,
12;; Wasmtime will handle by trapping.  In the future, once there's a host API for
13;; cancelling tasks, that behavior may change, in which case this test will need
14;; to be updated.
15(component
16
17  (component $A
18    (core func $backpressure.inc (canon backpressure.inc))
19    (core module $m
20      (import "" "backpressure.inc" (func $backpressure.inc))
21
22      (func (export "f") (result i32) unreachable)
23      (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
24
25      (func (export "turn-on-backpressure")
26        (call $backpressure.inc))
27    )
28
29    (core instance $i (instantiate $m
30      (with "" (instance
31        (export "backpressure.inc" (func $backpressure.inc))
32      ))
33    ))
34
35    (func (export "turn-on-backpressure") (canon lift (core func $i "turn-on-backpressure")))
36    (func (export "f")
37      (canon lift (core func $i "f") async (callback (func $i "callback"))))
38  )
39  (instance $A (instantiate $A))
40
41  (component $B
42    (import "A" (instance $A
43      (export "f" (func))
44      (export "turn-on-backpressure" (func))
45    ))
46
47    (core module $libc (memory (export "mem") 1))
48    (core instance $libc (instantiate $libc))
49
50    (core func $f (canon lower (func $A "f") async (memory $libc "mem")))
51    (core func $turn-on-backpressure (canon lower (func $A "turn-on-backpressure")))
52    (core func $waitable-set.new (canon waitable-set.new))
53    (core func $waitable.join (canon waitable.join))
54    (core func $waitable-set.wait (canon waitable-set.wait (memory $libc "mem")))
55
56    (core module $m
57      (import "" "f" (func $f (result i32)))
58      (import "" "turn-on-backpressure" (func $turn-on-backpressure))
59      (import "" "waitable-set.new" (func $waitable-set.new (result i32)))
60      (import "" "waitable.join" (func $waitable.join (param i32 i32)))
61      (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32)))
62
63      (func (export "f")
64        (local $status i32)
65        (local $set i32)
66        call $turn-on-backpressure
67
68        (local.set $status (call $f))
69
70        ;; low 4 bits should be "STARTING == 0"
71        (i32.ne
72          (i32.const 0)
73          (i32.and
74            (local.get $status)
75            (i32.const 0xf)))
76        if unreachable end
77
78        ;; make a new waitable set and join our subtask into it
79        (local.set $set (call $waitable-set.new))
80        (call $waitable.join
81          (i32.shr_u (local.get $status) (i32.const 4))
82          (local.get $set))
83
84        ;; block waiting for our task, which should deadlock (?)
85        (call $waitable-set.wait (local.get $set) (i32.const 0))
86        unreachable
87      )
88    )
89
90    (core instance $i (instantiate $m
91      (with "" (instance
92        (export "f" (func $f))
93        (export "turn-on-backpressure" (func $turn-on-backpressure))
94        (export "waitable-set.new" (func $waitable-set.new))
95        (export "waitable.join" (func $waitable.join))
96        (export "waitable-set.wait" (func $waitable-set.wait))
97      ))
98    ))
99
100    (func (export "f") async (canon lift (core func $i "f")))
101  )
102
103  (instance $B (instantiate $B (with "A" (instance $A))))
104
105  (func (export "f") (alias export $B "f"))
106)
107
108(assert_trap (invoke "f") "deadlock detected")
109