|
|
@@ -15,8 +15,8 @@ import (
|
|
|
// underlying buffer is an interface. (io.Pipe is always unbuffered)
|
|
|
type pipe struct {
|
|
|
mu sync.Mutex
|
|
|
- c sync.Cond // c.L lazily initialized to &p.mu
|
|
|
- b pipeBuffer
|
|
|
+ c sync.Cond // c.L lazily initialized to &p.mu
|
|
|
+ b pipeBuffer // nil when done reading
|
|
|
err error // read error once empty. non-nil means closed.
|
|
|
breakErr error // immediate read error (caller doesn't see rest of b)
|
|
|
donec chan struct{} // closed on error
|
|
|
@@ -32,6 +32,9 @@ type pipeBuffer interface {
|
|
|
func (p *pipe) Len() int {
|
|
|
p.mu.Lock()
|
|
|
defer p.mu.Unlock()
|
|
|
+ if p.b == nil {
|
|
|
+ return 0
|
|
|
+ }
|
|
|
return p.b.Len()
|
|
|
}
|
|
|
|
|
|
@@ -55,6 +58,7 @@ func (p *pipe) Read(d []byte) (n int, err error) {
|
|
|
p.readFn() // e.g. copy trailers
|
|
|
p.readFn = nil // not sticky like p.err
|
|
|
}
|
|
|
+ p.b = nil
|
|
|
return 0, p.err
|
|
|
}
|
|
|
p.c.Wait()
|
|
|
@@ -75,6 +79,9 @@ func (p *pipe) Write(d []byte) (n int, err error) {
|
|
|
if p.err != nil {
|
|
|
return 0, errClosedPipeWrite
|
|
|
}
|
|
|
+ if p.breakErr != nil {
|
|
|
+ return len(d), nil // discard when there is no reader
|
|
|
+ }
|
|
|
return p.b.Write(d)
|
|
|
}
|
|
|
|
|
|
@@ -109,6 +116,9 @@ func (p *pipe) closeWithError(dst *error, err error, fn func()) {
|
|
|
return
|
|
|
}
|
|
|
p.readFn = fn
|
|
|
+ if dst == &p.breakErr {
|
|
|
+ p.b = nil
|
|
|
+ }
|
|
|
*dst = err
|
|
|
p.closeDoneLocked()
|
|
|
}
|