]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: fix race on bodyEOFSignal.isClosed
authorDave Cheney <dave@cheney.net>
Thu, 11 Oct 2012 21:32:56 +0000 (08:32 +1100)
committerDave Cheney <dave@cheney.net>
Thu, 11 Oct 2012 21:32:56 +0000 (08:32 +1100)
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

index 651f3ce0081bf9b5d213b2e8c0d5f4fb18b40fc3..22e1bb4928fe2fecf202140639c0597304b9a6ea 100644 (file)
@@ -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