Commit f1b17536 authored by Dave Cheney's avatar Dave Cheney

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
parent 6720997f
...@@ -24,6 +24,7 @@ import ( ...@@ -24,6 +24,7 @@ import (
"os" "os"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"time" "time"
) )
...@@ -816,13 +817,13 @@ func responseIsKeepAlive(res *Response) bool { ...@@ -816,13 +817,13 @@ func responseIsKeepAlive(res *Response) bool {
type bodyEOFSignal struct { type bodyEOFSignal struct {
body io.ReadCloser body io.ReadCloser
fn func() fn func()
isClosed bool isClosed uint32 // atomic bool, non-zero if true
once sync.Once once sync.Once
} }
func (es *bodyEOFSignal) Read(p []byte) (n int, err error) { func (es *bodyEOFSignal) Read(p []byte) (n int, err error) {
n, err = es.body.Read(p) 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") panic("http: unexpected bodyEOFSignal Read after Close; see issue 1725")
} }
if err == io.EOF { if err == io.EOF {
...@@ -832,10 +833,10 @@ func (es *bodyEOFSignal) Read(p []byte) (n int, err error) { ...@@ -832,10 +833,10 @@ func (es *bodyEOFSignal) Read(p []byte) (n int, err error) {
} }
func (es *bodyEOFSignal) Close() (err error) { func (es *bodyEOFSignal) Close() (err error) {
if es.isClosed { if !es.setClosed() {
// already closed
return nil return nil
} }
es.isClosed = true
err = es.body.Close() err = es.body.Close()
if err == nil { if err == nil {
es.condfn() es.condfn()
...@@ -849,6 +850,14 @@ func (es *bodyEOFSignal) 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 { type readFirstCloseBoth struct {
io.ReadCloser io.ReadCloser
io.Closer io.Closer
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment