Skip to content

Commit e96c63c

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

8 files changed

Lines changed: 1218 additions & 0 deletions

File tree

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
;; This test contains two components $C and $D that test cancelling reads
2+
;; and writes in the presence and absence of partial reads/writes.
3+
;;
4+
;; $C exports a function 'start-stream' that creates and holds onto a writable
5+
;; stream in the global $sw as well as various operations that operate on $sw.
6+
;; $D calls $C.start-stream to get the readable end and then drives the test.
7+
(component
8+
(component $C
9+
(core module $Memory (memory (export "mem") 1))
10+
(core instance $memory (instantiate $Memory))
11+
(core module $CM
12+
(import "" "mem" (memory 1))
13+
(import "" "task.return" (func $task.return (param i32)))
14+
(import "" "stream.new" (func $stream.new (result i64)))
15+
(import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32)))
16+
(import "" "stream.cancel-write" (func $stream.cancel-write (param i32) (result i32)))
17+
(import "" "stream.close-writable" (func $stream.close-writable (param i32)))
18+
19+
(global $sw (mut i32) (i32.const 0))
20+
21+
(func $start-stream (export "start-stream") (result i32)
22+
;; create a new stream, return the readable end to the caller
23+
(local $ret64 i64)
24+
(local.set $ret64 (call $stream.new))
25+
(global.set $sw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32))))
26+
(i32.wrap_i64 (local.get $ret64))
27+
)
28+
29+
(func $write4 (export "write4")
30+
;; write 6 bytes into the stream, expecting to rendezvous with a stream.read
31+
(local $ret i32)
32+
(i32.store (i32.const 8) (i32.const 0xabcd))
33+
(local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 4)))
34+
(if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret))
35+
(then unreachable))
36+
)
37+
38+
(func $write4-and-close (export "write4-and-close")
39+
(call $write4)
40+
(call $stream.close-writable (global.get $sw))
41+
)
42+
43+
(func $start-blocking-write (export "start-blocking-write")
44+
(local $ret i32)
45+
46+
;; prepare the write buffer
47+
(i64.store (i32.const 8) (i64.const 0x123456789abcdef))
48+
49+
;; start one blocking write and immediately cancel it
50+
(local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 8)))
51+
(if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret))
52+
(then unreachable))
53+
(local.set $ret (call $stream.cancel-write (global.get $sw)))
54+
(if (i32.ne (i32.const 0x2 (; CANCELLED ;)) (local.get $ret))
55+
(then unreachable))
56+
57+
;; start a second blockign write and leave it pending
58+
(local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 8)))
59+
(if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret))
60+
(then unreachable))
61+
)
62+
63+
(func $cancel-after-read4 (export "cancel-after-read4")
64+
(local $ret i32)
65+
(local.set $ret (call $stream.cancel-write (global.get $sw)))
66+
(; TODO: currently returns 0x40 ;)
67+
(if (i32.ne (i32.const 0x42 (; CANCELLED=2 | (4<<4) ;)) (local.get $ret))
68+
(then unreachable))
69+
)
70+
)
71+
(type $ST (stream u8))
72+
(canon task.return (result u32) (core func $task.return))
73+
(canon stream.new $ST (core func $stream.new))
74+
(canon stream.write $ST async (memory $memory "mem") (core func $stream.write))
75+
(canon stream.cancel-write $ST (core func $stream.cancel-write))
76+
(canon stream.close-writable $ST (core func $stream.close-writable))
77+
(core instance $cm (instantiate $CM (with "" (instance
78+
(export "mem" (memory $memory "mem"))
79+
(export "task.return" (func $task.return))
80+
(export "stream.new" (func $stream.new))
81+
(export "stream.write" (func $stream.write))
82+
(export "stream.cancel-write" (func $stream.cancel-write))
83+
(export "stream.close-writable" (func $stream.close-writable))
84+
))))
85+
(func (export "start-stream") (result (stream u8)) (canon lift (core func $cm "start-stream")))
86+
(func (export "write4") (canon lift (core func $cm "write4")))
87+
(func (export "write4-and-close") (canon lift (core func $cm "write4-and-close")))
88+
(func (export "start-blocking-write") (canon lift (core func $cm "start-blocking-write")))
89+
(func (export "cancel-after-read4") (canon lift (core func $cm "cancel-after-read4")))
90+
)
91+
92+
(component $D
93+
(import "c" (instance $c
94+
(export "start-stream" (func (result (stream u8))))
95+
(export "write4" (func))
96+
(export "write4-and-close" (func))
97+
(export "start-blocking-write" (func))
98+
(export "cancel-after-read4" (func))
99+
))
100+
101+
(core module $Memory (memory (export "mem") 1))
102+
(core instance $memory (instantiate $Memory))
103+
(core module $DM
104+
(import "" "mem" (memory 1))
105+
(import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32)))
106+
(import "" "stream.cancel-read" (func $stream.cancel-read (param i32) (result i32)))
107+
(import "" "stream.close-readable" (func $stream.close-readable (param i32)))
108+
(import "" "start-stream" (func $start-stream (result i32)))
109+
(import "" "write4" (func $write4))
110+
(import "" "write4-and-close" (func $write4-and-close))
111+
(import "" "start-blocking-write" (func $start-blocking-write))
112+
(import "" "cancel-after-read4" (func $cancel-after-read4))
113+
114+
(func $run (export "run") (result i32)
115+
(local $ret i32)
116+
(local $sr i32)
117+
118+
;; call 'start-stream' to get the stream we'll be working with
119+
(local.set $sr (call $start-stream))
120+
(if (i32.ne (i32.const 1) (local.get $sr))
121+
(then unreachable))
122+
123+
;; start read that will block
124+
(local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100)))
125+
(if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret))
126+
(then unreachable))
127+
128+
;; cancelling it will finish without anything having been written
129+
(local.set $ret (call $stream.cancel-read (local.get $sr)))
130+
(if (i32.ne (i32.const 0x2 (; CANCELLED ;)) (local.get $ret))
131+
(then unreachable))
132+
133+
;; read, block, call $C to write 4 bytes into the buffer,
134+
;; then cancel, which should show "4+cancelled"
135+
(local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100)))
136+
(if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret))
137+
(then unreachable))
138+
(call $write4)
139+
(local.set $ret (call $stream.cancel-read (local.get $sr)))
140+
(; TODO: currently returns 0x40 ;)
141+
(if (i32.ne (i32.const 0x42 (; CANCELLED=2 | (4<<4) ;)) (local.get $ret))
142+
(then unreachable))
143+
(if (i32.ne (i32.const 0xabcd) (i32.load (i32.const 8)))
144+
(then unreachable))
145+
146+
;; read, block, call $C to write 4 bytes into the buffer and close,
147+
;; then cancel, which should show "4+closed"
148+
(local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100)))
149+
(if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret))
150+
(then unreachable))
151+
(call $write4-and-close)
152+
(local.set $ret (call $stream.cancel-read (local.get $sr)))
153+
(; TODO: currently returns 0x40 ;)
154+
(if (i32.ne (i32.const 0x41 (; CLOSED=1 | (4<<4) ;)) (local.get $ret))
155+
(then unreachable))
156+
(if (i32.ne (i32.const 0xabcd) (i32.load (i32.const 8)))
157+
(then unreachable))
158+
(call $stream.close-readable (local.get $sr))
159+
160+
;; get a new $sr
161+
(local.set $sr (call $start-stream))
162+
(if (i32.ne (i32.const 1) (local.get $sr))
163+
(then unreachable))
164+
165+
;; start outstanding write in $C, read 4 of it, then call back into $C
166+
;; which will cancel and see 4 written.
167+
(call $start-blocking-write)
168+
(local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 4)))
169+
(if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret))
170+
(then unreachable))
171+
(if (i32.ne (i32.const 0x89abcdef) (i32.load (i32.const 8)))
172+
(then unreachable))
173+
(call $cancel-after-read4)
174+
175+
;; return 42 to the top-level assert_return
176+
(i32.const 42)
177+
)
178+
)
179+
(type $ST (stream u8))
180+
(canon stream.read $ST async (memory $memory "mem") (core func $stream.read))
181+
(canon stream.cancel-read $ST (core func $stream.cancel-read))
182+
(canon stream.close-readable $ST (core func $stream.close-readable))
183+
(canon lower (func $c "start-stream") (core func $start-stream'))
184+
(canon lower (func $c "write4") (core func $write4'))
185+
(canon lower (func $c "write4-and-close") (core func $write4-and-close'))
186+
(canon lower (func $c "start-blocking-write") (core func $start-blocking-write'))
187+
(canon lower (func $c "cancel-after-read4") (core func $cancel-after-read4'))
188+
(core instance $dm (instantiate $DM (with "" (instance
189+
(export "mem" (memory $memory "mem"))
190+
(export "stream.read" (func $stream.read))
191+
(export "stream.cancel-read" (func $stream.cancel-read))
192+
(export "stream.close-readable" (func $stream.close-readable))
193+
(export "start-stream" (func $start-stream'))
194+
(export "write4" (func $write4'))
195+
(export "write4-and-close" (func $write4-and-close'))
196+
(export "start-blocking-write" (func $start-blocking-write'))
197+
(export "cancel-after-read4" (func $cancel-after-read4'))
198+
))))
199+
(func (export "run") (result u32) (canon lift (core func $dm "run")))
200+
)
201+
202+
(instance $c (instantiate $C))
203+
(instance $d (instantiate $D (with "c" (instance $c))))
204+
(func (export "run") (alias export $d "run"))
205+
)
206+
(assert_return (invoke "run") (u32.const 42))
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
;; This test contains two components $C and $D where $D imports and calls $C.
2+
;; $D.run calls $C.f, which blocks on an empty waitable set
3+
;; $D.run then subtask.cancels $C.f, which resumes $C.f which promptly resolves
4+
;; without returning a value.
5+
(component
6+
(component $C
7+
(core module $Memory (memory (export "mem") 1))
8+
(core instance $memory (instantiate $Memory))
9+
(core module $CM
10+
(import "" "mem" (memory 1))
11+
(import "" "task.cancel" (func $task.cancel))
12+
(import "" "waitable.join" (func $waitable.join (param i32 i32)))
13+
(import "" "waitable-set.new" (func $waitable-set.new (result i32)))
14+
(import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32)))
15+
16+
;; $ws is waited on by 'f'
17+
(global $ws (mut i32) (i32.const 0))
18+
(func $start (global.set $ws (call $waitable-set.new)))
19+
(start $start)
20+
21+
(func $f (export "f") (result i32)
22+
;; wait on $ws which is currently empty, expected to get cancelled
23+
(i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4)))
24+
)
25+
(func $f_cb (export "f_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32)
26+
;; confirm that we've received a cancellation request
27+
(if (i32.ne (local.get $event_code) (i32.const 6 (; TASK_CANCELLED ;)))
28+
(then unreachable))
29+
(if (i32.ne (local.get $index) (i32.const 0))
30+
(then unreachable))
31+
(if (i32.ne (local.get $payload) (i32.const 0))
32+
(then unreachable))
33+
34+
;; finish without returning a value
35+
(call $task.cancel)
36+
(i32.const 0 (; EXIT ;))
37+
)
38+
)
39+
(type $FT (future))
40+
(canon task.cancel (core func $task.cancel))
41+
(canon waitable.join (core func $waitable.join))
42+
(canon waitable-set.new (core func $waitable-set.new))
43+
(canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait))
44+
(canon future.new $FT (core func $future.new))
45+
(canon future.read $FT async (memory $memory "mem") (core func $future.read))
46+
(canon future.write $FT async (memory $memory "mem") (core func $future.write))
47+
(canon future.close-readable $FT (core func $future.close-readable))
48+
(canon future.close-writable $FT (core func $future.close-writable))
49+
(core instance $cm (instantiate $CM (with "" (instance
50+
(export "mem" (memory $memory "mem"))
51+
(export "task.cancel" (func $task.cancel))
52+
(export "waitable.join" (func $waitable.join))
53+
(export "waitable-set.new" (func $waitable-set.new))
54+
(export "waitable-set.wait" (func $waitable-set.wait))
55+
(export "future.new" (func $future.new))
56+
(export "future.read" (func $future.read))
57+
(export "future.write" (func $future.write))
58+
(export "future.close-readable" (func $future.close-readable))
59+
(export "future.close-writable" (func $future.close-writable))
60+
))))
61+
(func (export "f") (result u32) (canon lift
62+
(core func $cm "f")
63+
async (callback (func $cm "f_cb"))
64+
))
65+
)
66+
67+
(component $D
68+
(import "f" (func $f (result u32)))
69+
70+
(core module $Memory (memory (export "mem") 1))
71+
(core instance $memory (instantiate $Memory))
72+
(core module $DM
73+
(import "" "mem" (memory 1))
74+
(import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32)))
75+
(import "" "subtask.drop" (func $subtask.drop (param i32)))
76+
(import "" "f" (func $f (param i32 i32) (result i32)))
77+
78+
(func $run (export "run") (result i32)
79+
(local $ret i32) (local $retp i32)
80+
(local $subtask i32)
81+
(local $event_code i32)
82+
83+
;; call 'f'; it should block
84+
(local.set $retp (i32.const 4))
85+
(i32.store (local.get $retp) (i32.const 0xbad0bad0))
86+
(local.set $ret (call $f (i32.const 0xdeadbeef) (local.get $retp)))
87+
(if (i32.ne (i32.const 1 (; STARTING ;)) (i32.and (local.get $ret) (i32.const 0xf)))
88+
(then unreachable))
89+
(local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4)))
90+
91+
;; cancel 'f'; it should complete without blocking
92+
(local.set $ret (call $subtask.cancel (local.get $subtask)))
93+
(if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (local.get $ret))
94+
(then unreachable))
95+
96+
;; The $retp memory shouldn't have changed
97+
(if (i32.ne (i32.load (local.get $retp)) (i32.const 0xbad0bad0))
98+
(then unreachable))
99+
100+
(call $subtask.drop (local.get $subtask))
101+
102+
;; return to the top-level assert_return
103+
(i32.const 42)
104+
)
105+
)
106+
(canon subtask.cancel (core func $subtask.cancel))
107+
(canon subtask.drop (core func $subtask.drop))
108+
(canon lower (func $f) async (memory $memory "mem") (core func $f'))
109+
(core instance $dm (instantiate $DM (with "" (instance
110+
(export "mem" (memory $memory "mem"))
111+
(export "subtask.cancel" (func $subtask.cancel))
112+
(export "subtask.drop" (func $subtask.drop))
113+
(export "f" (func $f'))
114+
))))
115+
(func (export "run") (result u32) (canon lift (core func $dm "run")))
116+
)
117+
118+
(instance $c (instantiate $C))
119+
(instance $d (instantiate $D (with "f" (func $c "f"))))
120+
(func (export "run") (alias export $d "run"))
121+
)
122+
(assert_return (invoke "run") (u32.const 42))

0 commit comments

Comments
 (0)