@@ -3,7 +3,6 @@ package multistream
3
3
import (
4
4
"fmt"
5
5
"io"
6
- "sync"
7
6
)
8
7
9
8
// NewMSSelect returns a new Multistream which is able to perform
@@ -12,6 +11,9 @@ func NewMSSelect[T StringLike](c io.ReadWriteCloser, proto T) LazyConn {
12
11
return & lazyClientConn [T ]{
13
12
protos : []T {ProtocolID , proto },
14
13
con : c ,
14
+
15
+ rhandshakeOnce : newOnceFunc (),
16
+ whandshakeOnce : newOnceFunc (),
15
17
}
16
18
}
17
19
@@ -25,6 +27,34 @@ func NewMultistream[T StringLike](c io.ReadWriteCloser, proto T) LazyConn {
25
27
}
26
28
}
27
29
30
+ // onceFunc is a sync.Once that can be used by synctest.
31
+ // For the Multistream, it is a bit better than sync.Once because it doesn't
32
+ // spin when acquiring the lock.
33
+ type onceFunc struct {
34
+ sem chan struct {}
35
+ }
36
+
37
+ func newOnceFunc () * onceFunc {
38
+ o := onceFunc {
39
+ sem : make (chan struct {}, 1 ),
40
+ }
41
+ o .sem <- struct {}{}
42
+ return & o
43
+ }
44
+
45
+ func (o * onceFunc ) Do (f func ()) {
46
+ // We only ever pull a single value from the channel. But we want to block
47
+ // Do until the first call to Do has completed. The first call will close
48
+ // the channel, so by checking if it's closed we know we don't need to do
49
+ // anything.
50
+ _ , ok := <- o .sem
51
+ if ! ok {
52
+ return
53
+ }
54
+ defer close (o .sem )
55
+ f ()
56
+ }
57
+
28
58
// lazyClientConn is a ReadWriteCloser adapter that lazily negotiates a protocol
29
59
// using multistream-select on first use.
30
60
//
@@ -33,11 +63,11 @@ func NewMultistream[T StringLike](c io.ReadWriteCloser, proto T) LazyConn {
33
63
// See: https://github.com/multiformats/go-multistream/issues/20
34
64
type lazyClientConn [T StringLike ] struct {
35
65
// Used to ensure we only trigger the write half of the handshake once.
36
- rhandshakeOnce sync. Once
66
+ rhandshakeOnce * onceFunc
37
67
rerr error
38
68
39
69
// Used to ensure we only trigger the read half of the handshake once.
40
- whandshakeOnce sync. Once
70
+ whandshakeOnce * onceFunc
41
71
werr error
42
72
43
73
// The sequence of protocols to negotiate.
0 commit comments