瀏覽代碼

lib/protocol: Ensure starting & closing a connection are exclusive (fixes #9102) (#9103)

In principle a connection can close while it's in progress with
starting, and then it's undefined if we wait for goroutines to exit etc.
With this change, we will wait for start to complete before starting to
stop everything.
Jakob Borg 2 年之前
父節點
當前提交
f47de83914
共有 1 個文件被更改,包括 5 次插入0 次删除
  1. 5 0
      lib/protocol/protocol.go

+ 5 - 0
lib/protocol/protocol.go

@@ -208,6 +208,7 @@ type rawConnection struct {
 	closeOnce             sync.Once
 	closeOnce             sync.Once
 	sendCloseOnce         sync.Once
 	sendCloseOnce         sync.Once
 	compression           Compression
 	compression           Compression
+	startStopMut          sync.Mutex // start and stop must be serialized
 
 
 	loopWG sync.WaitGroup // Need to ensure no leftover routines in testing
 	loopWG sync.WaitGroup // Need to ensure no leftover routines in testing
 }
 }
@@ -295,6 +296,8 @@ func newRawConnection(deviceID DeviceID, reader io.Reader, writer io.Writer, clo
 // Start creates the goroutines for sending and receiving of messages. It must
 // Start creates the goroutines for sending and receiving of messages. It must
 // be called exactly once after creating a connection.
 // be called exactly once after creating a connection.
 func (c *rawConnection) Start() {
 func (c *rawConnection) Start() {
+	c.startStopMut.Lock()
+	defer c.startStopMut.Unlock()
 	c.loopWG.Add(5)
 	c.loopWG.Add(5)
 	go func() {
 	go func() {
 		c.readerLoop()
 		c.readerLoop()
@@ -963,6 +966,8 @@ func (c *rawConnection) Close(err error) {
 
 
 // internalClose is called if there is an unexpected error during normal operation.
 // internalClose is called if there is an unexpected error during normal operation.
 func (c *rawConnection) internalClose(err error) {
 func (c *rawConnection) internalClose(err error) {
+	c.startStopMut.Lock()
+	defer c.startStopMut.Unlock()
 	c.closeOnce.Do(func() {
 	c.closeOnce.Do(func() {
 		l.Debugf("close connection to %s at %s due to %v", c.deviceID.Short(), c.ConnectionInfo, err)
 		l.Debugf("close connection to %s at %s due to %v", c.deviceID.Short(), c.ConnectionInfo, err)
 		if cerr := c.closer.Close(); cerr != nil {
 		if cerr := c.closer.Close(); cerr != nil {