Fix cc.Close() state race
Fix a race condition in which a Conn's state is set to TransientFailure after Close() has been invoked – Close() should irrevocably set state to Shutdown.
diff --git a/clientconn.go b/clientconn.go
index 4729bbd..6da8867 100644
--- a/clientconn.go
+++ b/clientconn.go
@@ -359,6 +359,7 @@
cc.mu.Lock()
cc.printf("connecting")
if cc.state == Shutdown {
+ // cc.Close() has been invoked.
cc.mu.Unlock()
return ErrClientConnClosing
}
@@ -393,6 +394,11 @@
newTransport, err := transport.NewClientTransport(cc.target, &copts)
if err != nil {
cc.mu.Lock()
+ if cc.state == Shutdown {
+ // cc.Close() has been invoked.
+ cc.mu.Unlock()
+ return ErrClientConnClosing
+ }
cc.errorf("transient failure: %v", err)
cc.state = TransientFailure
cc.stateCV.Broadcast()
@@ -450,6 +456,11 @@
return
case <-cc.transport.Error():
cc.mu.Lock()
+ if cc.state == Shutdown {
+ // cc.Close() has been invoked.
+ cc.mu.Unlock()
+ return
+ }
cc.state = TransientFailure
cc.stateCV.Broadcast()
cc.mu.Unlock()