22b955cca5
Reviewed-on: https://go-review.googlesource.com/25150 From-SVN: r238662
192 lines
4.5 KiB
Go
192 lines
4.5 KiB
Go
// Copyright 2009 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.
|
|
|
|
// Pipe adapter to connect code expecting an io.Reader
|
|
// with code expecting an io.Writer.
|
|
|
|
package io
|
|
|
|
import (
|
|
"errors"
|
|
"sync"
|
|
)
|
|
|
|
// ErrClosedPipe is the error used for read or write operations on a closed pipe.
|
|
var ErrClosedPipe = errors.New("io: read/write on closed pipe")
|
|
|
|
// A pipe is the shared pipe structure underlying PipeReader and PipeWriter.
|
|
type pipe struct {
|
|
rl sync.Mutex // gates readers one at a time
|
|
wl sync.Mutex // gates writers one at a time
|
|
l sync.Mutex // protects remaining fields
|
|
data []byte // data remaining in pending write
|
|
rwait sync.Cond // waiting reader
|
|
wwait sync.Cond // waiting writer
|
|
rerr error // if reader closed, error to give writes
|
|
werr error // if writer closed, error to give reads
|
|
}
|
|
|
|
func (p *pipe) read(b []byte) (n int, err error) {
|
|
// One reader at a time.
|
|
p.rl.Lock()
|
|
defer p.rl.Unlock()
|
|
|
|
p.l.Lock()
|
|
defer p.l.Unlock()
|
|
for {
|
|
if p.rerr != nil {
|
|
return 0, ErrClosedPipe
|
|
}
|
|
if p.data != nil {
|
|
break
|
|
}
|
|
if p.werr != nil {
|
|
return 0, p.werr
|
|
}
|
|
p.rwait.Wait()
|
|
}
|
|
n = copy(b, p.data)
|
|
p.data = p.data[n:]
|
|
if len(p.data) == 0 {
|
|
p.data = nil
|
|
p.wwait.Signal()
|
|
}
|
|
return
|
|
}
|
|
|
|
var zero [0]byte
|
|
|
|
func (p *pipe) write(b []byte) (n int, err error) {
|
|
// pipe uses nil to mean not available
|
|
if b == nil {
|
|
b = zero[:]
|
|
}
|
|
|
|
// One writer at a time.
|
|
p.wl.Lock()
|
|
defer p.wl.Unlock()
|
|
|
|
p.l.Lock()
|
|
defer p.l.Unlock()
|
|
if p.werr != nil {
|
|
err = ErrClosedPipe
|
|
return
|
|
}
|
|
p.data = b
|
|
p.rwait.Signal()
|
|
for {
|
|
if p.data == nil {
|
|
break
|
|
}
|
|
if p.rerr != nil {
|
|
err = p.rerr
|
|
break
|
|
}
|
|
if p.werr != nil {
|
|
err = ErrClosedPipe
|
|
}
|
|
p.wwait.Wait()
|
|
}
|
|
n = len(b) - len(p.data)
|
|
p.data = nil // in case of rerr or werr
|
|
return
|
|
}
|
|
|
|
func (p *pipe) rclose(err error) {
|
|
if err == nil {
|
|
err = ErrClosedPipe
|
|
}
|
|
p.l.Lock()
|
|
defer p.l.Unlock()
|
|
p.rerr = err
|
|
p.rwait.Signal()
|
|
p.wwait.Signal()
|
|
}
|
|
|
|
func (p *pipe) wclose(err error) {
|
|
if err == nil {
|
|
err = EOF
|
|
}
|
|
p.l.Lock()
|
|
defer p.l.Unlock()
|
|
p.werr = err
|
|
p.rwait.Signal()
|
|
p.wwait.Signal()
|
|
}
|
|
|
|
// A PipeReader is the read half of a pipe.
|
|
type PipeReader struct {
|
|
p *pipe
|
|
}
|
|
|
|
// Read implements the standard Read interface:
|
|
// it reads data from the pipe, blocking until a writer
|
|
// arrives or the write end is closed.
|
|
// If the write end is closed with an error, that error is
|
|
// returned as err; otherwise err is EOF.
|
|
func (r *PipeReader) Read(data []byte) (n int, err error) {
|
|
return r.p.read(data)
|
|
}
|
|
|
|
// Close closes the reader; subsequent writes to the
|
|
// write half of the pipe will return the error ErrClosedPipe.
|
|
func (r *PipeReader) Close() error {
|
|
return r.CloseWithError(nil)
|
|
}
|
|
|
|
// CloseWithError closes the reader; subsequent writes
|
|
// to the write half of the pipe will return the error err.
|
|
func (r *PipeReader) CloseWithError(err error) error {
|
|
r.p.rclose(err)
|
|
return nil
|
|
}
|
|
|
|
// A PipeWriter is the write half of a pipe.
|
|
type PipeWriter struct {
|
|
p *pipe
|
|
}
|
|
|
|
// Write implements the standard Write interface:
|
|
// it writes data to the pipe, blocking until readers
|
|
// have consumed all the data or the read end is closed.
|
|
// If the read end is closed with an error, that err is
|
|
// returned as err; otherwise err is ErrClosedPipe.
|
|
func (w *PipeWriter) Write(data []byte) (n int, err error) {
|
|
return w.p.write(data)
|
|
}
|
|
|
|
// Close closes the writer; subsequent reads from the
|
|
// read half of the pipe will return no bytes and EOF.
|
|
func (w *PipeWriter) Close() error {
|
|
return w.CloseWithError(nil)
|
|
}
|
|
|
|
// CloseWithError closes the writer; subsequent reads from the
|
|
// read half of the pipe will return no bytes and the error err,
|
|
// or EOF if err is nil.
|
|
//
|
|
// CloseWithError always returns nil.
|
|
func (w *PipeWriter) CloseWithError(err error) error {
|
|
w.p.wclose(err)
|
|
return nil
|
|
}
|
|
|
|
// Pipe creates a synchronous in-memory pipe.
|
|
// It can be used to connect code expecting an io.Reader
|
|
// with code expecting an io.Writer.
|
|
// Reads on one end are matched with writes on the other,
|
|
// copying data directly between the two; there is no internal buffering.
|
|
// It is safe to call Read and Write in parallel with each other or with
|
|
// Close. Close will complete once pending I/O is done. Parallel calls to
|
|
// Read, and parallel calls to Write, are also safe:
|
|
// the individual calls will be gated sequentially.
|
|
func Pipe() (*PipeReader, *PipeWriter) {
|
|
p := new(pipe)
|
|
p.rwait.L = &p.l
|
|
p.wwait.L = &p.l
|
|
r := &PipeReader{p}
|
|
w := &PipeWriter{p}
|
|
return r, w
|
|
}
|