Skip to content

Commit 83b69b7

Browse files
committed
Add some wast tests for async
1 parent 935c478 commit 83b69b7

8 files changed

Lines changed: 889 additions & 0 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
TODO
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
TODO

test/concurrency/deadlock.wast

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
;; This test defines components $C and $D where $D imports and calls $C
2+
;; $C.f waits on an empty waitable set
3+
;; $D.g calls $C.f and then waits for it to finish, which fails due to deadlock
4+
(component
5+
(component $C
6+
(core module $Memory (memory (export "mem") 1))
7+
(core instance $memory (instantiate $Memory))
8+
(core module $CM
9+
(import "" "mem" (memory 1))
10+
(import "" "waitable-set.new" (func $waitable-set.new (result i32)))
11+
12+
(func (export "f") (result i32)
13+
;; wait on a new empty waitable set
14+
(local $ws i32)
15+
(local.set $ws (call $waitable-set.new))
16+
(i32.or (i32.const 2 (; WAIT ;)) (i32.shl (local.get $ws) (i32.const 4)))
17+
)
18+
(func (export "cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32)
19+
unreachable
20+
)
21+
)
22+
(canon waitable-set.new (core func $waitable-set.new))
23+
(core instance $cm (instantiate $CM (with "" (instance
24+
(export "mem" (memory $memory "mem"))
25+
(export "waitable-set.new" (func $waitable-set.new))
26+
))))
27+
(func (export "f") (result u32) (canon lift
28+
(core func $cm "f")
29+
async (memory $memory "mem") (callback (func $cm "cb"))
30+
))
31+
)
32+
33+
(component $D
34+
(import "f" (func $f (result u32)))
35+
36+
(core module $Memory (memory (export "mem") 1))
37+
(core instance $memory (instantiate $Memory))
38+
(core module $DM
39+
(import "" "mem" (memory 1))
40+
(import "" "waitable.join" (func $waitable.join (param i32 i32)))
41+
(import "" "waitable-set.new" (func $waitable-set.new (result i32)))
42+
(import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32)))
43+
(import "" "f" (func $f (param i32 i32) (result i32)))
44+
45+
(func (export "g") (result i32)
46+
(local $ws i32) (local $ret i32) (local $subtaski i32)
47+
(local.set $ret (call $f (i32.const 0) (i32.const 0)))
48+
(local.set $subtaski (i32.shr_u (local.get $ret) (i32.const 4)))
49+
(local.set $ws (call $waitable-set.new))
50+
(call $waitable.join (local.get $subtaski) (local.get $ws))
51+
(call $waitable-set.wait (local.get $ws) (i32.const 0))
52+
unreachable
53+
)
54+
)
55+
(canon waitable.join (core func $waitable.join))
56+
(canon waitable-set.new (core func $waitable-set.new))
57+
(canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait))
58+
(canon lower (func $f) async (memory $memory "mem") (core func $f'))
59+
(core instance $dm (instantiate $DM (with "" (instance
60+
(export "mem" (memory $memory "mem"))
61+
(export "waitable.join" (func $waitable.join))
62+
(export "waitable-set.new" (func $waitable-set.new))
63+
(export "waitable-set.wait" (func $waitable-set.wait))
64+
(export "f" (func $f'))
65+
))))
66+
(func (export "f") (result u32) (canon lift (core func $dm "g")))
67+
)
68+
69+
(instance $c (instantiate $C))
70+
(instance $d (instantiate $D (with "f" (func $c "f"))))
71+
(func (export "f") (alias export $d "f"))
72+
)
73+
(assert_trap (invoke "f") "wasm trap: deadlock detected: event loop cannot make further progress")

test/concurrency/empty-wait.wast

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
;; This test has two components $C and $D, where $D imports and calls $C
2+
;; $C exports two functions: 'blocker' and 'unblocker'
3+
;; 'blocker' blocks on an empty waitable set
4+
;; 'unblocker' wakes blocker by adding a resolved future to blocker's waitable set
5+
;; $D calls 'blocker' then 'unblocker', then waits for 'blocker' to finish
6+
(component
7+
(component $C
8+
(core module $Memory (memory (export "mem") 1))
9+
(core instance $memory (instantiate $Memory))
10+
(core module $CM
11+
(import "" "mem" (memory 1))
12+
(import "" "task.return" (func $task.return (param i32)))
13+
(import "" "waitable.join" (func $waitable.join (param i32 i32)))
14+
(import "" "waitable-set.new" (func $waitable-set.new (result i32)))
15+
(import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32)))
16+
(import "" "future.new" (func $future.new (result i64)))
17+
(import "" "future.read" (func $future.read (param i32 i32) (result i32)))
18+
(import "" "future.write" (func $future.write (param i32 i32) (result i32)))
19+
(import "" "future.close-readable" (func $future.close-readable (param i32)))
20+
(import "" "future.close-writable" (func $future.close-writable (param i32)))
21+
22+
;; $ws is waited on by 'blocker' and added to by 'unblocker'
23+
(global $ws (mut i32) (i32.const 0))
24+
(func $start (global.set $ws (call $waitable-set.new)))
25+
(start $start)
26+
27+
;; 'unblocker' initializes $futr with the readable end of a resolved future
28+
(global $futr (mut i32) (i32.const 0))
29+
30+
(func $blocker (export "blocker") (result i32)
31+
;; wait on $ws which is currently empty; 'unblocker' will wake us up
32+
(i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4)))
33+
)
34+
(func $blocker_cb (export "blocker_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32)
35+
;; assert that we were in fact woken by 'unblocker' adding $futr to $ws
36+
(if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code))
37+
(then unreachable))
38+
(if (i32.ne (global.get $futr) (local.get $index))
39+
(then unreachable))
40+
(if (i32.ne (i32.const 0x11 (; TODO: instead of 0x10 ;)) (local.get $payload))
41+
(then unreachable))
42+
43+
(call $future.close-readable (global.get $futr))
44+
45+
;; return 42 to $D.run
46+
(call $task.return (i32.const 42))
47+
(i32.const 0)
48+
)
49+
50+
(func $unblocker (export "unblocker") (result i32)
51+
(local $ret i32) (local $ret64 i64)
52+
(local $futw i32)
53+
54+
;; create a future that will be used to unblock 'blocker', storing r/w ends in $futr/$futw
55+
(local.set $ret64 (call $future.new))
56+
(global.set $futr (i32.wrap_i64 (local.get $ret64)))
57+
(if (i32.ne (i32.const 2 (; TODO: instead of 3 ;)) (global.get $futr))
58+
(then unreachable))
59+
(local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32))))
60+
(if (i32.ne (i32.const 3 (; TODO: instead of 2 ;)) (local.get $futw))
61+
(then unreachable))
62+
63+
;; perform a future.read which will block, and add this future to the waitable-set
64+
;; being waited on by 'blocker'
65+
(local.set $ret (call $future.read (global.get $futr) (i32.const 0xdeadbeef)))
66+
(if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret))
67+
(then unreachable))
68+
(call $waitable.join (global.get $futr) (global.get $ws))
69+
70+
;; perform a future.write which will rendezvous with the write and complete
71+
(local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef)))
72+
(if (i32.ne (i32.const 0x11 (; TODO: instead of 0x10 ;)) (local.get $ret))
73+
(then unreachable))
74+
75+
(call $future.close-writable (local.get $futw))
76+
77+
;; return 43 to $D.run
78+
(call $task.return (i32.const 43))
79+
(i32.const 0)
80+
)
81+
(func $unblocker_cb (export "unblocker_cb") (param i32 i32 i32) (result i32)
82+
;; 'unblocker' doesn't block
83+
unreachable
84+
)
85+
)
86+
(type $FT (future))
87+
(canon task.return (result u32) (core func $task.return))
88+
(canon waitable.join (core func $waitable.join))
89+
(canon waitable-set.new (core func $waitable-set.new))
90+
(canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait))
91+
(canon future.new $FT (core func $future.new))
92+
(canon future.read $FT async (memory $memory "mem") (core func $future.read))
93+
(canon future.write $FT async (memory $memory "mem") (core func $future.write))
94+
(canon future.close-readable $FT (core func $future.close-readable))
95+
(canon future.close-writable $FT (core func $future.close-writable))
96+
(core instance $cm (instantiate $CM (with "" (instance
97+
(export "mem" (memory $memory "mem"))
98+
(export "task.return" (func $task.return))
99+
(export "waitable.join" (func $waitable.join))
100+
(export "waitable-set.new" (func $waitable-set.new))
101+
(export "waitable-set.wait" (func $waitable-set.wait))
102+
(export "future.new" (func $future.new))
103+
(export "future.read" (func $future.read))
104+
(export "future.write" (func $future.write))
105+
(export "future.close-readable" (func $future.close-readable))
106+
(export "future.close-writable" (func $future.close-writable))
107+
))))
108+
(func (export "blocker") (result u32) (canon lift
109+
(core func $cm "blocker")
110+
async (callback (func $cm "blocker_cb"))
111+
))
112+
(func (export "unblocker") (result u32) (canon lift
113+
(core func $cm "unblocker")
114+
async (callback (func $cm "unblocker_cb"))
115+
))
116+
)
117+
118+
(component $D
119+
(import "c" (instance $c
120+
(export "blocker" (func (result u32)))
121+
(export "unblocker" (func (result u32)))
122+
))
123+
124+
(core module $Memory (memory (export "mem") 1))
125+
(core instance $memory (instantiate $Memory))
126+
(core module $DM
127+
(import "" "mem" (memory 1))
128+
(import "" "waitable.join" (func $waitable.join (param i32 i32)))
129+
(import "" "waitable-set.new" (func $waitable-set.new (result i32)))
130+
(import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32)))
131+
(import "" "blocker" (func $blocker (param i32 i32) (result i32)))
132+
(import "" "unblocker" (func $unblocker (param i32 i32) (result i32)))
133+
134+
(global $ws (mut i32) (i32.const 0))
135+
(func $start (global.set $ws (call $waitable-set.new)))
136+
(start $start)
137+
138+
(func $run (export "run") (result i32)
139+
(local $ret i32) (local $retp1 i32) (local $retp2 i32)
140+
(local $subtask i32)
141+
(local $event_code i32)
142+
143+
;; call 'blocker'; it should block
144+
(local.set $retp1 (i32.const 4))
145+
(local.set $ret (call $blocker (i32.const 0xdeadbeef) (local.get $retp1)))
146+
(if (i32.ne (i32.const 1 (; STARTING ;)) (i32.and (local.get $ret) (i32.const 0xf)))
147+
(then unreachable))
148+
(local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4)))
149+
(if (i32.ne (i32.const 2) (local.get $subtask))
150+
(then unreachable))
151+
152+
;; call 'unblocker' to unblock 'blocker'; it should complete eagerly
153+
(local.set $retp2 (i32.const 8))
154+
(local.set $ret (call $unblocker (i32.const 0xbeefdead) (local.get $retp2)))
155+
(if (i32.ne (i32.const 0 (; TODO: instead of 2 ;)) (local.get $ret))
156+
(then unreachable))
157+
(if (i32.ne (i32.const 43) (i32.load (local.get $retp2)))
158+
(then unreachable))
159+
160+
;; wait for 'blocker' to be scheduled, run, and return
161+
(call $waitable.join (local.get $subtask) (global.get $ws))
162+
(local.set $retp2 (i32.const 8))
163+
(local.set $event_code (call $waitable-set.wait (global.get $ws) (local.get $retp2)))
164+
(if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code))
165+
(then unreachable))
166+
(if (i32.ne (local.get $subtask) (i32.load (local.get $retp2)))
167+
(then unreachable))
168+
(if (i32.ne (i32.const 2 (; RETURNED ;)) (i32.load offset=4 (local.get $retp2)))
169+
(then unreachable))
170+
(if (i32.ne (i32.const 42) (i32.load (local.get $retp1)))
171+
(then unreachable))
172+
173+
;; return 44 to the top-level test harness
174+
(i32.const 44)
175+
)
176+
)
177+
(canon waitable.join (core func $waitable.join))
178+
(canon waitable-set.new (core func $waitable-set.new))
179+
(canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait))
180+
(canon lower (func $c "blocker") async (memory $memory "mem") (core func $blocker'))
181+
(canon lower (func $c "unblocker") async (memory $memory "mem") (core func $unblocker'))
182+
(core instance $dm (instantiate $DM (with "" (instance
183+
(export "mem" (memory $memory "mem"))
184+
(export "waitable.join" (func $waitable.join))
185+
(export "waitable-set.new" (func $waitable-set.new))
186+
(export "waitable-set.wait" (func $waitable-set.wait))
187+
(export "blocker" (func $blocker'))
188+
(export "unblocker" (func $unblocker'))
189+
))))
190+
(func (export "run") (result u32) (canon lift (core func $dm "run")))
191+
)
192+
193+
(instance $c (instantiate $C))
194+
(instance $d (instantiate $D (with "c" (instance $c))))
195+
(func (export "run") (alias export $d "run"))
196+
)
197+
(assert_return (invoke "run") (u32.const 44))

0 commit comments

Comments
 (0)