"os"
"strings"
"sync"
+ "sync/atomic"
"time"
)
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 {
}
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()
}
}
+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