@@ -11,26 +11,92 @@ func Run() {
1111 write := make (chan wit_types.Unit )
1212 read := make (chan wit_types.Unit )
1313
14- tx , rx := test .MakeStreamUnit ()
15- go func () {
16- assertEqual (tx .Write ([]wit_types.Unit {wit_types.Unit {}}), 1 )
17- assert (! tx .ReaderDropped ())
14+ {
15+ tx , rx := test .MakeStreamUnit ()
16+ go func () {
17+ assertEqual (tx .Write ([]wit_types.Unit {wit_types.Unit {}}), 1 )
18+ assert (! tx .ReaderDropped ())
1819
19- assertEqual (tx .Write ([]wit_types.Unit {wit_types.Unit {}, wit_types.Unit {}}), 2 )
20+ assertEqual (tx .Write ([]wit_types.Unit {wit_types.Unit {}, wit_types.Unit {}}), 2 )
2021
21- assertEqual (tx .Write ([]wit_types.Unit {wit_types.Unit {}, wit_types.Unit {}}), 0 )
22- assert (tx .ReaderDropped ())
22+ assertEqual (tx .Write ([]wit_types.Unit {wit_types.Unit {}, wit_types.Unit {}}), 0 )
23+ assert (tx .ReaderDropped ())
2324
24- write <- wit_types.Unit {}
25- }()
25+ write <- wit_types.Unit {}
26+ }()
2627
27- go func () {
28- test .ReadStream (rx )
29- read <- wit_types.Unit {}
30- }()
28+ go func () {
29+ test .ReadStream (rx )
30+ read <- wit_types.Unit {}
31+ }()
32+
33+ (<- read )
34+ (<- write )
35+ }
36+
37+ {
38+ tx , rx := test .MakeStreamUnit ()
39+ syncBarrier := make (chan struct {})
40+ panicCh := make (chan any , 2 )
41+
42+ for range 2 {
43+ go func () {
44+ // Because the channel is empty, it will block until it's closed, at which
45+ // point all Goroutines will attempt to simultaneously read from the stream.
46+ <- syncBarrier
47+ panicCh <- checkPanicValue (func () {
48+ result := make ([]wit_types.Unit , 1 )
49+ rx .Read (result )
50+ })
51+ }()
52+ }
53+ close (syncBarrier )
54+
55+ go func () {
56+ // If this is omitted, the host will see that the "rx.Read" operations aren't paired with
57+ // a "tx.WriteAll" and will result in a "wasm trap: deadlock detected" error. Additionally,
58+ // this is placed after "close(syncBarrier)" to ensure that the panics are resulting from
59+ // concurrent reads, and not from other scenarios that result in a nil handle.
60+ tx .WriteAll ([]wit_types.Unit {wit_types.Unit {}})
61+ }()
62+
63+ p1 , p2 := <- panicCh , <- panicCh
64+
65+ // One should succeed (nil), one should panic
66+ assert ((p1 == nil && p2 == "nil handle" ) || (p1 == "nil handle" && p2 == nil ))
67+ }
68+
69+ {
70+ tx , rx := test .MakeStreamUnit ()
71+ syncBarrier := make (chan struct {})
72+ panicCh := make (chan any , 2 )
73+
74+ for range 2 {
75+ go func () {
76+ // Because the channel is empty, it will block until it's closed, at which
77+ // point all Goroutines will attempt to simultaneously write to the stream.
78+ <- syncBarrier
79+ panicCh <- checkPanicValue (func () {
80+ tx .WriteAll ([]wit_types.Unit {wit_types.Unit {}})
81+ })
82+ }()
83+ }
84+ close (syncBarrier )
85+
86+ go func () {
87+ // If this is omitted, the host will see that the "tx.WriteAll" operations aren't paired with
88+ // an "rx.Read" and will result in a "wasm trap: deadlock detected" error. Additionally,
89+ // this is placed after "close(syncBarrier)" to ensure that the panics are resulting from
90+ // concurrent writes, and not from other scenarios that result in a nil handle.
91+ result := make ([]wit_types.Unit , 1 )
92+ rx .Read (result )
93+ }()
94+
95+ p1 , p2 := <- panicCh , <- panicCh
3196
32- (<- read )
33- (<- write )
97+ // One should succeed (nil), one should panic
98+ assert ((p1 == nil && p2 == "nil handle" ) || (p1 == "nil handle" && p2 == nil ))
99+ }
34100}
35101
36102func assertEqual [T comparable ](a , b T ) {
@@ -44,3 +110,11 @@ func assert(v bool) {
44110 panic ("assertion failed" )
45111 }
46112}
113+
114+ func checkPanicValue (f func ()) (value any ) {
115+ defer func () {
116+ value = recover ()
117+ }()
118+ f ()
119+ return nil
120+ }
0 commit comments