Skip to content

Commit 8360a76

Browse files
committed
Add test/async/drop-cross-task-borrow.wast
1 parent 2ea91ee commit 8360a76

1 file changed

Lines changed: 204 additions & 0 deletions

File tree

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
;; This test has 3 components $C, $D and $E
2+
;; $C just implements a resource type that's used by $D and $E
3+
;; $E calls async function $D.dont-drop, lending it a handle.
4+
;; $D.dont-drop blocks, waiting on an empty waitable-set
5+
;; $E then calls $D.drop-handle which drops the handle that $D.dont-drop
6+
;; was lent, albeit from the "wrong" task ($D.drop-handle).
7+
;; Then $E calls $D.resume-dont-drop to unblock $D.dont-drop, which
8+
;; will call task.return which should not trap.
9+
(component definition $Test
10+
(component $C
11+
(type $R' (resource (rep i32)))
12+
(canon resource.new $R' (core func $resource.new))
13+
(core module $CM (func (export "id") (param i32) (result i32) (local.get 0)))
14+
(core instance $cm (instantiate $CM))
15+
(alias core export $cm "id" (core func $resource.rep))
16+
(export $R "R" (type $R'))
17+
(func (export "R-new") (param "rep" u32) (result (own $R)) (canon lift (core func $resource.new)))
18+
(func (export "R-rep") (param "self" (borrow $R)) (result u32) (canon lift (core func $resource.rep)))
19+
)
20+
21+
(component $D
22+
(import "c" (instance $d
23+
(export "R" (type $R (sub resource)))
24+
(export "R-new" (func (param "rep" u32) (result (own $R))))
25+
(export "R-rep" (func (param "self" (borrow $R)) (result u32)))
26+
))
27+
(core module $DM
28+
(import "" "waitable.join" (func $waitable.join (param i32 i32)))
29+
(import "" "waitable-set.new" (func $waitable-set.new (result i32)))
30+
(import "" "future.new" (func $future.new (result i64)))
31+
(import "" "future.read" (func $future.read (param i32 i32) (result i32)))
32+
(import "" "future.write" (func $future.write (param i32 i32) (result i32)))
33+
(import "" "task.return" (func $task.return (param i32)))
34+
(import "" "R-rep" (func $R-rep (param i32) (result i32)))
35+
(import "" "R-drop" (func $R-drop (param i32)))
36+
37+
(global $handle (mut i32) (i32.const 0))
38+
(global $dont-drop-result (mut i32) (i32.const 0))
39+
(global $dont-drop-ws (mut i32) (i32.const 0))
40+
41+
(func (export "dont-drop") (param $h i32) (result i32)
42+
;; Stash the given (borrow $R) handle in a global.
43+
(global.set $handle (local.get $h))
44+
;; Stash the result of $R-rep in a global for later task.return
45+
(global.set $dont-drop-result (call $R-rep (local.get $h)))
46+
;; Stash the waitable-set we're waiting on in a global for resume-dont-drop to use
47+
(global.set $dont-drop-ws (call $waitable-set.new))
48+
(i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $dont-drop-ws) (i32.const 4)))
49+
)
50+
(func (export "dont-drop-cb") (param i32 i32 i32) (result i32)
51+
;; We were resumed by resume-dont-drop
52+
(call $task.return (global.get $dont-drop-result))
53+
(i32.const 0 (; EXIT ;))
54+
)
55+
(func (export "drop-handle") (result i32)
56+
;; Drops the borrowed handle passed to dont-drop
57+
(local $result i32)
58+
(local.set $result (call $R-rep (global.get $handle)))
59+
(call $R-drop (global.get $handle))
60+
(local.get $result)
61+
)
62+
(func (export "resume-dont-drop")
63+
;; Add a waitable with a pending event to dont-drop's waitable-set to
64+
;; wake it up.
65+
(local $ret i32) (local $ret64 i64)
66+
(local $futw i32) (local $futr i32)
67+
(local.set $ret64 (call $future.new))
68+
(local.set $futr (i32.wrap_i64 (local.get $ret64)))
69+
(local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32))))
70+
(local.set $ret (call $future.read (local.get $futr) (i32.const 0xdeadbeef)))
71+
(if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret))
72+
(then unreachable))
73+
(local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef)))
74+
(if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret))
75+
(then unreachable))
76+
(call $waitable.join (local.get $futr) (global.get $dont-drop-ws))
77+
)
78+
)
79+
(type $FT (future))
80+
(alias export $d "R" (type $R))
81+
(canon task.return (result u32) (core func $task.return))
82+
(canon waitable.join (core func $waitable.join))
83+
(canon waitable-set.new (core func $waitable-set.new))
84+
(canon future.new $FT (core func $future.new))
85+
(canon future.read $FT async (core func $future.read))
86+
(canon future.write $FT async (core func $future.write))
87+
(canon lower (func $d "R-rep") (core func $R-rep))
88+
(canon resource.drop $R (core func $R-drop))
89+
(core instance $dm (instantiate $DM (with "" (instance
90+
(export "task.return" (func $task.return))
91+
(export "waitable.join" (func $waitable.join))
92+
(export "waitable-set.new" (func $waitable-set.new))
93+
(export "future.new" (func $future.new))
94+
(export "future.read" (func $future.read))
95+
(export "future.write" (func $future.write))
96+
(export "R-rep" (func $R-rep))
97+
(export "R-drop" (func $R-drop))
98+
))))
99+
(func (export "dont-drop") async (param "self" (borrow $R)) (result u32)
100+
(canon lift (core func $dm "dont-drop") async (callback (func $dm "dont-drop-cb")))
101+
)
102+
(func (export "drop-handle") (result u32)
103+
(canon lift (core func $dm "drop-handle"))
104+
)
105+
(func (export "resume-dont-drop")
106+
(canon lift (core func $dm "resume-dont-drop"))
107+
)
108+
)
109+
110+
(component $E
111+
(import "c" (instance $c
112+
(export "R" (type $R (sub resource)))
113+
(export "R-new" (func (param "rep" u32) (result (own $R))))
114+
))
115+
(alias export $c "R" (type $R))
116+
(import "d" (instance $d
117+
(export "dont-drop" (func async (param "self" (borrow $R)) (result u32)))
118+
(export "drop-handle" (func (result u32)))
119+
(export "resume-dont-drop" (func))
120+
))
121+
(core module $Memory (memory (export "mem") 1))
122+
(core instance $memory (instantiate $Memory))
123+
(core module $EM
124+
(import "" "mem" (memory 1))
125+
(import "" "waitable.join" (func $waitable.join (param i32 i32)))
126+
(import "" "waitable-set.new" (func $waitable-set.new (result i32)))
127+
(import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32)))
128+
(import "" "R-new" (func $R-new (param i32) (result i32)))
129+
(import "" "dont-drop" (func $dont-drop (param i32 i32) (result i32)))
130+
(import "" "drop-handle" (func $drop-handle (result i32)))
131+
(import "" "resume-dont-drop" (func $resume-dont-drop))
132+
(func (export "do-it-right") (result i32)
133+
(local $ret i32)
134+
(local $retp i32) (local $retp2 i32)
135+
(local $handle i32)
136+
(local $subtask i32)
137+
(local $magic i32)
138+
(local $ws i32) (local $event_code i32)
139+
140+
;; Create a resource storign $magic as it's rep
141+
(local.set $magic (i32.const 10))
142+
(local.set $handle (call $R-new (local.get $magic)))
143+
144+
;; Kick off a call to dont-drop that will block
145+
(local.set $retp (i32.const 16))
146+
(local.set $ret (call $dont-drop (local.get $handle) (local.get $retp)))
147+
(if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf)))
148+
(then unreachable))
149+
(local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4)))
150+
151+
;; drop-handle should return the rep of the handle passed to dont-drop
152+
(local.set $ret (call $drop-handle))
153+
(if (i32.ne (local.get $magic) (local.get $ret))
154+
(then unreachable))
155+
156+
;; this unblocks $subtask
157+
(call $resume-dont-drop)
158+
159+
;; now wait for $subtask to return, so that it can run before the test is over
160+
(local.set $ws (call $waitable-set.new))
161+
(call $waitable.join (local.get $subtask) (local.get $ws))
162+
(local.set $retp2 (i32.const 32))
163+
(local.set $event_code (call $waitable-set.wait (local.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=2 | (0<<4) ;)) (i32.load offset=4 (local.get $retp2)))
169+
(then unreachable))
170+
171+
;; $subtask should return the rep passed to $R-new.
172+
(if (i32.ne (local.get $magic) (i32.load (local.get $retp)))
173+
(then unreachable))
174+
175+
i32.const 42
176+
)
177+
)
178+
(canon waitable.join (core func $waitable.join))
179+
(canon waitable-set.new (core func $waitable-set.new))
180+
(canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait))
181+
(canon lower (func $c "R-new") (core func $R-new))
182+
(canon lower (func $d "dont-drop") async (memory $memory "mem") (core func $dont-drop))
183+
(canon lower (func $d "drop-handle") (core func $drop-handle))
184+
(canon lower (func $d "resume-dont-drop") (core func $resume-dont-drop))
185+
(core instance $em (instantiate $EM (with "" (instance
186+
(export "mem" (memory $memory "mem"))
187+
(export "waitable.join" (func $waitable.join))
188+
(export "waitable-set.new" (func $waitable-set.new))
189+
(export "waitable-set.wait" (func $waitable-set.wait))
190+
(export "R-new" (func $R-new))
191+
(export "dont-drop" (func $dont-drop))
192+
(export "drop-handle" (func $drop-handle))
193+
(export "resume-dont-drop" (func $resume-dont-drop))
194+
))))
195+
(func (export "do-it-right") async (result u32) (canon lift (core func $em "do-it-right")))
196+
)
197+
(instance $c (instantiate $C))
198+
(instance $d (instantiate $D (with "c" (instance $c))))
199+
(instance $e (instantiate $E (with "c" (instance $c)) (with "d" (instance $d))))
200+
(func (export "do-it-right") (alias export $e "do-it-right"))
201+
)
202+
203+
(component instance $i $Test)
204+
(assert_return (invoke "do-it-right") (u32.const 42))

0 commit comments

Comments
 (0)