// Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package http2 import ( "errors" "io" "sync" ) // pipe is a goroutine-safe io.Reader/io.Writer pair. It's like // io.Pipe except there are no PipeReader/PipeWriter halves, and the // underlying buffer is an interface. (io.Pipe is always unbuffered) type pipe struct { mu sync.Mutex c sync.Cond // c.L must point to b pipeBuffer err error // read error once empty. non-nil means closed. } type pipeBuffer interface { Len() int io.Writer io.Reader } // Read waits until data is available and copies bytes // from the buffer into p. func (p *pipe) Read(d []byte) (n int, err error) { p.mu.Lock() defer p.mu.Unlock() if p.c.L == nil { p.c.L = &p.mu } for { if p.b.Len() > 0 { return p.b.Read(d) } if p.err != nil { return 0, p.err } p.c.Wait() } } var errClosedPipeWrite = errors.New("write on closed buffer") // Write copies bytes from p into the buffer and wakes a reader. // It is an error to write more data than the buffer can hold. func (p *pipe) Write(d []byte) (n int, err error) { p.mu.Lock() defer p.mu.Unlock() if p.c.L == nil { p.c.L = &p.mu } defer p.c.Signal() if p.err != nil { return 0, errClosedPipeWrite } return p.b.Write(d) } // CloseWithError causes Reads to wake up and return the // provided err after all data has been read. // // The error must be non-nil. func (p *pipe) CloseWithError(err error) { if err == nil { panic("CloseWithError must be non-nil") } p.mu.Lock() defer p.mu.Unlock() if p.c.L == nil { p.c.L = &p.mu } defer p.c.Signal() if p.err == nil { p.err = err } } // Err returns the error (if any) first set with CloseWithError. // This is the error which will be returned after the reader is exhausted. func (p *pipe) Err() error { p.mu.Lock() defer p.mu.Unlock() return p.err }