From f1b1753627d1f895baa53e41c6fb4301282a3760 Mon Sep 17 00:00:00 2001 From: Dave Cheney Date: Fri, 12 Oct 2012 08:32:56 +1100 Subject: [PATCH] net/http: fix race on bodyEOFSignal.isClosed Update #4191. Fixes unreported race failure at http://build.golang.org/log/61e43a328fb220801d3d5c88cd91916cfc5dc43c R=dvyukov, bradfitz CC=golang-dev https://golang.org/cl/6640057 --- src/pkg/net/http/transport.go | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/pkg/net/http/transport.go b/src/pkg/net/http/transport.go index 651f3ce008..22e1bb4928 100644 --- a/src/pkg/net/http/transport.go +++ b/src/pkg/net/http/transport.go @@ -24,6 +24,7 @@ import ( "os" "strings" "sync" + "sync/atomic" "time" ) @@ -816,13 +817,13 @@ func responseIsKeepAlive(res *Response) bool { type bodyEOFSignal struct { body io.ReadCloser fn func() - isClosed bool + isClosed uint32 // atomic bool, non-zero if true once sync.Once } func (es *bodyEOFSignal) Read(p []byte) (n int, err error) { n, err = es.body.Read(p) - if es.isClosed && n > 0 { + if es.closed() && n > 0 { panic("http: unexpected bodyEOFSignal Read after Close; see issue 1725") } if err == io.EOF { @@ -832,10 +833,10 @@ func (es *bodyEOFSignal) Read(p []byte) (n int, err error) { } func (es *bodyEOFSignal) Close() (err error) { - if es.isClosed { + if !es.setClosed() { + // already closed return nil } - es.isClosed = true err = es.body.Close() if err == nil { es.condfn() @@ -849,6 +850,14 @@ func (es *bodyEOFSignal) condfn() { } } +func (es *bodyEOFSignal) closed() bool { + return atomic.LoadUint32(&es.isClosed) != 0 +} + +func (es *bodyEOFSignal) setClosed() bool { + return atomic.CompareAndSwapUint32(&es.isClosed, 0, 1) +} + type readFirstCloseBoth struct { io.ReadCloser io.Closer -- 2.48.1