Skip to content

Commit e683264

Browse files
committed
Add more stream/future WAST tests
1 parent e5ee0af commit e683264

4 files changed

Lines changed: 562 additions & 0 deletions

File tree

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
;; Test that DROPPED doesn't override COMPLETED for futures.
2+
(component definition $Tester
3+
(core module $Memory (memory (export "mem") 1))
4+
(core instance $memory (instantiate $Memory))
5+
(core module $M
6+
(import "" "mem" (memory 1))
7+
(import "" "waitable.join" (func $waitable.join (param i32 i32)))
8+
(import "" "waitable-set.new" (func $waitable-set.new (result i32)))
9+
(import "" "waitable-set.poll" (func $waitable-set.poll (param i32 i32) (result i32)))
10+
(import "" "future.new" (func $future.new (result i64)))
11+
(import "" "future.read" (func $future.read (param i32 i32) (result i32)))
12+
(import "" "future.write" (func $future.write (param i32 i32) (result i32)))
13+
(import "" "future.drop-readable" (func $future.drop-readable (param i32)))
14+
(import "" "future.drop-writable" (func $future.drop-writable (param i32)))
15+
16+
;; The event returned by waitable-set.poll is stored at [0,8): the waitable
17+
;; index at 0 and the payload at 4. The source byte lives at 64, the
18+
;; destination byte at 128.
19+
(global $ws (mut i32) (i32.const 0))
20+
(global $rx (mut i32) (i32.const 0))
21+
(global $tx (mut i32) (i32.const 0))
22+
23+
(func $start
24+
(global.set $ws (call $waitable-set.new))
25+
(i32.store8 (i32.const 64) (i32.const 1))
26+
)
27+
(start $start)
28+
29+
(func $expect-event (param $code i32) (param $index i32) (param $payload i32)
30+
(if (i32.ne (call $waitable-set.poll (global.get $ws) (i32.const 0)) (local.get $code))
31+
(then unreachable))
32+
(if (i32.ne (i32.load (i32.const 0)) (local.get $index))
33+
(then unreachable))
34+
(if (i32.ne (i32.load (i32.const 4)) (local.get $payload))
35+
(then unreachable))
36+
)
37+
(func $expect-no-event
38+
(if (i32.ne (call $waitable-set.poll (global.get $ws) (i32.const 0))
39+
(i32.const 0 (; NONE ;)))
40+
(then unreachable))
41+
)
42+
(func $new-future
43+
(local $ret64 i64)
44+
(local.set $ret64 (call $future.new))
45+
(global.set $rx (i32.wrap_i64 (local.get $ret64)))
46+
(global.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32))))
47+
)
48+
49+
;; The reader blocks first, so future.write consumes the writer's own
50+
;; completion inline. The writable end is then done and may be dropped
51+
;; before the reader has observed anything.
52+
(func (export "writer-completes-inline") (result i32)
53+
(call $new-future)
54+
(call $waitable.join (global.get $rx) (global.get $ws))
55+
(if (i32.ne (call $future.read (global.get $rx) (i32.const 128))
56+
(i32.const -1 (; BLOCKED ;)))
57+
(then unreachable))
58+
(if (i32.ne (call $future.write (global.get $tx) (i32.const 64))
59+
(i32.const 0 (; COMPLETED ;)))
60+
(then unreachable))
61+
(call $future.drop-writable (global.get $tx))
62+
;; COMPLETED, not DROPPED: the copy happened before the drop
63+
(call $expect-event (i32.const 4 (; FUTURE_READ ;)) (global.get $rx)
64+
(i32.const 0 (; COMPLETED ;)))
65+
(call $expect-no-event)
66+
(if (i32.ne (i32.load8_u (i32.const 128)) (i32.const 1))
67+
(then unreachable))
68+
(i32.const 42)
69+
)
70+
71+
;; The mirror: the writer blocks first, so future.read consumes the
72+
;; reader's completion inline and the blocked writer polls for its own.
73+
(func (export "reader-completes-inline") (result i32)
74+
(call $new-future)
75+
(call $waitable.join (global.get $tx) (global.get $ws))
76+
(if (i32.ne (call $future.write (global.get $tx) (i32.const 64))
77+
(i32.const -1 (; BLOCKED ;)))
78+
(then unreachable))
79+
(if (i32.ne (call $future.read (global.get $rx) (i32.const 128))
80+
(i32.const 0 (; COMPLETED ;)))
81+
(then unreachable))
82+
(call $future.drop-readable (global.get $rx))
83+
(call $expect-event (i32.const 5 (; FUTURE_WRITE ;)) (global.get $tx)
84+
(i32.const 0 (; COMPLETED ;)))
85+
(call $expect-no-event)
86+
(call $waitable.join (global.get $tx) (i32.const 0))
87+
(call $future.drop-writable (global.get $tx))
88+
(if (i32.ne (i32.load8_u (i32.const 128)) (i32.const 1))
89+
(then unreachable))
90+
(i32.const 42)
91+
)
92+
)
93+
(type $FT (future u8))
94+
(canon waitable.join (core func $waitable.join))
95+
(canon waitable-set.new (core func $waitable-set.new))
96+
(canon waitable-set.poll (memory (core memory $memory "mem")) (core func $waitable-set.poll))
97+
(canon future.new $FT (core func $future.new))
98+
(canon future.read $FT async (memory (core memory $memory "mem")) (core func $future.read))
99+
(canon future.write $FT async (memory (core memory $memory "mem")) (core func $future.write))
100+
(canon future.drop-readable $FT (core func $future.drop-readable))
101+
(canon future.drop-writable $FT (core func $future.drop-writable))
102+
(core instance $m (instantiate $M (with "" (instance
103+
(export "mem" (memory $memory "mem"))
104+
(export "waitable.join" (func $waitable.join))
105+
(export "waitable-set.new" (func $waitable-set.new))
106+
(export "waitable-set.poll" (func $waitable-set.poll))
107+
(export "future.new" (func $future.new))
108+
(export "future.read" (func $future.read))
109+
(export "future.write" (func $future.write))
110+
(export "future.drop-readable" (func $future.drop-readable))
111+
(export "future.drop-writable" (func $future.drop-writable))
112+
))))
113+
(func (export "writer-completes-inline") (result u32) (canon lift (core func $m "writer-completes-inline")))
114+
(func (export "reader-completes-inline") (result u32) (canon lift (core func $m "reader-completes-inline")))
115+
)
116+
(component instance $i $Tester)
117+
(assert_return (invoke "writer-completes-inline") (u32.const 42))
118+
(component instance $i $Tester)
119+
(assert_return (invoke "reader-completes-inline") (u32.const 42))

test/async/partial-stream-copies.wast

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,3 +236,135 @@
236236
(func (export "run") (alias export $d "run"))
237237
)
238238
(assert_return (invoke "run") (u32.const 42))
239+
240+
;; Test where the writer has a pending buffer that is drained by several reads
241+
;; and then the readable end is dropped (before the writer has observed its event).
242+
(component definition $Tester
243+
(core module $Memory (memory (export "mem") 1))
244+
(core instance $memory (instantiate $Memory))
245+
(core module $M
246+
(import "" "mem" (memory 1))
247+
(import "" "waitable.join" (func $waitable.join (param i32 i32)))
248+
(import "" "waitable-set.new" (func $waitable-set.new (result i32)))
249+
(import "" "waitable-set.poll" (func $waitable-set.poll (param i32 i32) (result i32)))
250+
(import "" "stream.new" (func $stream.new (result i64)))
251+
(import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32)))
252+
(import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32)))
253+
(import "" "stream.drop-readable" (func $stream.drop-readable (param i32)))
254+
255+
(global $ws (mut i32) (i32.const 0))
256+
(global $rx (mut i32) (i32.const 0))
257+
(global $tx (mut i32) (i32.const 0))
258+
259+
(func $start
260+
(global.set $ws (call $waitable-set.new))
261+
)
262+
(start $start)
263+
264+
(func $expect-event (param $code i32) (param $index i32) (param $payload i32)
265+
(if (i32.ne (call $waitable-set.poll (global.get $ws) (i32.const 0)) (local.get $code))
266+
(then unreachable))
267+
(if (i32.ne (i32.load (i32.const 0)) (local.get $index))
268+
(then unreachable))
269+
(if (i32.ne (i32.load (i32.const 4)) (local.get $payload))
270+
(then unreachable))
271+
)
272+
(func $expect-no-event
273+
(if (i32.ne (call $waitable-set.poll (global.get $ws) (i32.const 0))
274+
(i32.const 0 (; NONE ;)))
275+
(then unreachable))
276+
)
277+
;; Create a stream and block a 4-byte write on it, with the writable end in
278+
;; the waitable set so that its completion is observable.
279+
(func $blocked-write (param $n i32)
280+
(local $ret64 i64)
281+
(local.set $ret64 (call $stream.new))
282+
(global.set $rx (i32.wrap_i64 (local.get $ret64)))
283+
(global.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32))))
284+
(call $waitable.join (global.get $tx) (global.get $ws))
285+
(i32.store (i32.const 64) (i32.const 0x04030201))
286+
(if (i32.ne (call $stream.write (global.get $tx) (i32.const 64) (local.get $n))
287+
(i32.const -1 (; BLOCKED ;)))
288+
(then unreachable))
289+
)
290+
291+
;; A blocked 3-byte write is drained by a 1-byte then a 2-byte read. The
292+
;; reads see the bytes in order, and the writer gets one event carrying the
293+
;; total progress, not one event per read.
294+
(func (export "writer-buffer-pending") (result i32)
295+
(call $blocked-write (i32.const 3))
296+
(if (i32.ne (call $stream.read (global.get $rx) (i32.const 128) (i32.const 1))
297+
(i32.const 0x10 (; COMPLETED=0 | (1<<4) ;)))
298+
(then unreachable))
299+
;; NB: the writer is not polled in between -- observing its event would
300+
;; detach its buffer and the second read would have nothing to drain.
301+
(if (i32.ne (call $stream.read (global.get $rx) (i32.const 129) (i32.const 2))
302+
(i32.const 0x20 (; COMPLETED=0 | (2<<4) ;)))
303+
(then unreachable))
304+
(call $expect-event (i32.const 3 (; STREAM_WRITE ;)) (global.get $tx)
305+
(i32.const 0x30 (; COMPLETED=0 | (3<<4) ;)))
306+
(call $expect-no-event)
307+
;; bytes 1,2,3 landed contiguously and in order
308+
(if (i32.ne (i32.load (i32.const 128)) (i32.const 0x00030201))
309+
(then unreachable))
310+
(i32.const 42)
311+
)
312+
313+
;; If the readable end is dropped before the writer observes its event, the
314+
;; pending COMPLETED is folded into a DROPPED carrying the same progress:
315+
;; the writer learns both that its bytes were copied and that the stream is
316+
;; over, in one event.
317+
(func (export "drop-folds-into-full-progress") (result i32)
318+
(call $blocked-write (i32.const 4))
319+
(if (i32.ne (call $stream.read (global.get $rx) (i32.const 128) (i32.const 4))
320+
(i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)))
321+
(then unreachable))
322+
(call $stream.drop-readable (global.get $rx))
323+
(call $expect-event (i32.const 3 (; STREAM_WRITE ;)) (global.get $tx)
324+
(i32.const 0x41 (; DROPPED=1 | (4<<4) ;)))
325+
(call $expect-no-event)
326+
(i32.const 42)
327+
)
328+
329+
;; Same, with the write only partially drained: the folded event reports
330+
;; the partial progress.
331+
(func (export "drop-folds-into-partial-progress") (result i32)
332+
(call $blocked-write (i32.const 4))
333+
(if (i32.ne (call $stream.read (global.get $rx) (i32.const 128) (i32.const 2))
334+
(i32.const 0x20 (; COMPLETED=0 | (2<<4) ;)))
335+
(then unreachable))
336+
(call $stream.drop-readable (global.get $rx))
337+
(call $expect-event (i32.const 3 (; STREAM_WRITE ;)) (global.get $tx)
338+
(i32.const 0x21 (; DROPPED=1 | (2<<4) ;)))
339+
(call $expect-no-event)
340+
(i32.const 42)
341+
)
342+
)
343+
(type $ST (stream u8))
344+
(canon waitable.join (core func $waitable.join))
345+
(canon waitable-set.new (core func $waitable-set.new))
346+
(canon waitable-set.poll (memory (core memory $memory "mem")) (core func $waitable-set.poll))
347+
(canon stream.new $ST (core func $stream.new))
348+
(canon stream.read $ST async (memory (core memory $memory "mem")) (core func $stream.read))
349+
(canon stream.write $ST async (memory (core memory $memory "mem")) (core func $stream.write))
350+
(canon stream.drop-readable $ST (core func $stream.drop-readable))
351+
(core instance $m (instantiate $M (with "" (instance
352+
(export "mem" (memory $memory "mem"))
353+
(export "waitable.join" (func $waitable.join))
354+
(export "waitable-set.new" (func $waitable-set.new))
355+
(export "waitable-set.poll" (func $waitable-set.poll))
356+
(export "stream.new" (func $stream.new))
357+
(export "stream.read" (func $stream.read))
358+
(export "stream.write" (func $stream.write))
359+
(export "stream.drop-readable" (func $stream.drop-readable))
360+
))))
361+
(func (export "writer-buffer-pending") (result u32) (canon lift (core func $m "writer-buffer-pending")))
362+
(func (export "drop-folds-into-full-progress") (result u32) (canon lift (core func $m "drop-folds-into-full-progress")))
363+
(func (export "drop-folds-into-partial-progress") (result u32) (canon lift (core func $m "drop-folds-into-partial-progress")))
364+
)
365+
(component instance $i $Tester)
366+
(assert_return (invoke "writer-buffer-pending") (u32.const 42))
367+
(component instance $i $Tester)
368+
(assert_return (invoke "drop-folds-into-full-progress") (u32.const 42))
369+
(component instance $i $Tester)
370+
(assert_return (invoke "drop-folds-into-partial-progress") (u32.const 42))

0 commit comments

Comments
 (0)