From 0fd544f256c212485402a9cf27506fc33a098eeb Mon Sep 17 00:00:00 2001 From: Daniel Kwasnick Date: Tue, 10 Nov 2015 14:02:38 -0800 Subject: [PATCH] Fix cc.Close() state race MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- clientconn.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/clientconn.go b/clientconn.go index 4729bbd6abef..6da8867d6020 100644 --- a/clientconn.go +++ b/clientconn.go @@ -359,6 +359,7 @@ func (cc *Conn) resetTransport(closeTransport bool) error { cc.mu.Lock() cc.printf("connecting") if cc.state == Shutdown { + // cc.Close() has been invoked. cc.mu.Unlock() return ErrClientConnClosing } @@ -393,6 +394,11 @@ func (cc *Conn) resetTransport(closeTransport bool) error { 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 @@ func (cc *Conn) transportMonitor() { 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()