@@ -3,7 +3,6 @@ package multistream
33import (
44 "fmt"
55 "io"
6- "sync"
76)
87
98// NewMSSelect returns a new Multistream which is able to perform
@@ -12,6 +11,9 @@ func NewMSSelect[T StringLike](c io.ReadWriteCloser, proto T) LazyConn {
1211 return & lazyClientConn [T ]{
1312 protos : []T {ProtocolID , proto },
1413 con : c ,
14+
15+ rhandshakeOnce : newOnce (),
16+ whandshakeOnce : newOnce (),
1517 }
1618}
1719
@@ -22,7 +24,38 @@ func NewMultistream[T StringLike](c io.ReadWriteCloser, proto T) LazyConn {
2224 return & lazyClientConn [T ]{
2325 protos : []T {proto },
2426 con : c ,
27+
28+ rhandshakeOnce : newOnce (),
29+ whandshakeOnce : newOnce (),
30+ }
31+ }
32+
33+ // once is a sync.Once that can be used by synctest.
34+ // For Multistream, it is a bit better than sync.Once because it doesn't
35+ // spin when acquiring the lock.
36+ type once struct {
37+ sem chan struct {}
38+ }
39+
40+ func newOnce () * once {
41+ o := once {
42+ sem : make (chan struct {}, 1 ),
43+ }
44+ o .sem <- struct {}{}
45+ return & o
46+ }
47+
48+ func (o * once ) Do (f func ()) {
49+ // We only ever pull a single value from the channel. But we want to block
50+ // Do until the first call to Do has completed. The first call will close
51+ // the channel, so by checking if it's closed we know we don't need to do
52+ // anything.
53+ _ , ok := <- o .sem
54+ if ! ok {
55+ return
2556 }
57+ defer close (o .sem )
58+ f ()
2659}
2760
2861// lazyClientConn is a ReadWriteCloser adapter that lazily negotiates a protocol
@@ -33,11 +66,11 @@ func NewMultistream[T StringLike](c io.ReadWriteCloser, proto T) LazyConn {
3366// See: https://github.com/multiformats/go-multistream/issues/20
3467type lazyClientConn [T StringLike ] struct {
3568 // Used to ensure we only trigger the write half of the handshake once.
36- rhandshakeOnce sync. Once
69+ rhandshakeOnce * once
3770 rerr error
3871
3972 // Used to ensure we only trigger the read half of the handshake once.
40- whandshakeOnce sync. Once
73+ whandshakeOnce * once
4174 werr error
4275
4376 // The sequence of protocols to negotiate.
0 commit comments