2009-02-16 17:32:30 -07:00
|
|
|
// 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.Read
|
|
|
|
// with code expecting an io.Write.
|
|
|
|
|
|
|
|
package io
|
|
|
|
|
|
|
|
import (
|
|
|
|
"io";
|
|
|
|
"os";
|
|
|
|
"sync";
|
|
|
|
)
|
|
|
|
|
|
|
|
type pipeReturn struct {
|
|
|
|
n int;
|
2009-04-17 01:08:24 -06:00
|
|
|
err os.Error;
|
2009-02-16 17:32:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Shared pipe structure.
|
|
|
|
type pipe struct {
|
|
|
|
rclosed bool; // Read end closed?
|
|
|
|
wclosed bool; // Write end closed?
|
|
|
|
wpend []byte; // Written data waiting to be read.
|
|
|
|
wtot int; // Bytes consumed so far in current write.
|
|
|
|
cr chan []byte; // Write sends data here...
|
|
|
|
cw chan pipeReturn; // ... and reads the n, err back from here.
|
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (p *pipe) Read(data []byte) (n int, err os.Error) {
|
2009-02-16 17:32:30 -07:00
|
|
|
if p == nil || p.rclosed {
|
|
|
|
return 0, os.EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait for next write block if necessary.
|
|
|
|
if p.wpend == nil {
|
|
|
|
if !p.wclosed {
|
|
|
|
p.wpend = <-p.cr;
|
|
|
|
}
|
|
|
|
if p.wpend == nil {
|
2009-05-22 23:43:57 -06:00
|
|
|
return 0, nil;
|
2009-02-16 17:32:30 -07:00
|
|
|
}
|
|
|
|
p.wtot = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read from current write block.
|
|
|
|
n = len(data);
|
|
|
|
if n > len(p.wpend) {
|
|
|
|
n = len(p.wpend);
|
|
|
|
}
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
data[i] = p.wpend[i];
|
|
|
|
}
|
|
|
|
p.wtot += n;
|
|
|
|
p.wpend = p.wpend[n:len(p.wpend)];
|
|
|
|
|
|
|
|
// If write block is done, finish the write.
|
|
|
|
if len(p.wpend) == 0 {
|
|
|
|
p.wpend = nil;
|
2009-03-03 09:39:12 -07:00
|
|
|
p.cw <- pipeReturn{p.wtot, nil};
|
2009-02-16 17:32:30 -07:00
|
|
|
p.wtot = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return n, nil;
|
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (p *pipe) Write(data []byte) (n int, err os.Error) {
|
2009-02-16 17:32:30 -07:00
|
|
|
if p == nil || p.wclosed {
|
|
|
|
return 0, os.EINVAL;
|
|
|
|
}
|
|
|
|
if p.rclosed {
|
2009-05-22 23:43:57 -06:00
|
|
|
return 0, os.EPIPE;
|
2009-02-16 17:32:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Send data to reader.
|
|
|
|
p.cr <- data;
|
|
|
|
|
|
|
|
// Wait for reader to finish copying it.
|
|
|
|
res := <-p.cw;
|
|
|
|
return res.n, res.err;
|
|
|
|
}
|
|
|
|
|
2009-05-22 23:43:57 -06:00
|
|
|
func (p *pipe) CloseReader() os.Error {
|
2009-02-16 17:32:30 -07:00
|
|
|
if p == nil || p.rclosed {
|
|
|
|
return os.EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop any future writes.
|
|
|
|
p.rclosed = true;
|
|
|
|
|
|
|
|
// Stop the current write.
|
|
|
|
if !p.wclosed {
|
2009-05-22 23:43:57 -06:00
|
|
|
p.cw <- pipeReturn{p.wtot, os.EPIPE};
|
2009-02-16 17:32:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2009-05-22 23:43:57 -06:00
|
|
|
func (p *pipe) CloseWriter() os.Error {
|
2009-02-16 17:32:30 -07:00
|
|
|
if p == nil || p.wclosed {
|
|
|
|
return os.EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop any future reads.
|
|
|
|
p.wclosed = true;
|
|
|
|
|
|
|
|
// Stop the current read.
|
|
|
|
if !p.rclosed {
|
|
|
|
p.cr <- nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read/write halves of the pipe.
|
|
|
|
// They are separate structures for two reasons:
|
|
|
|
// 1. If one end becomes garbage without being Closed,
|
|
|
|
// its finisher can Close so that the other end
|
|
|
|
// does not hang indefinitely.
|
|
|
|
// 2. Clients cannot use interface conversions on the
|
|
|
|
// read end to find the Write method, and vice versa.
|
|
|
|
|
2009-05-22 23:43:57 -06:00
|
|
|
// Read half of pipe.
|
|
|
|
type pipeRead struct {
|
2009-02-16 17:32:30 -07:00
|
|
|
lock sync.Mutex;
|
|
|
|
p *pipe;
|
|
|
|
}
|
|
|
|
|
2009-05-22 23:43:57 -06:00
|
|
|
func (r *pipeRead) Read(data []byte) (n int, err os.Error) {
|
2009-02-16 17:32:30 -07:00
|
|
|
r.lock.Lock();
|
|
|
|
defer r.lock.Unlock();
|
|
|
|
|
|
|
|
return r.p.Read(data);
|
|
|
|
}
|
|
|
|
|
2009-05-22 23:43:57 -06:00
|
|
|
func (r *pipeRead) Close() os.Error {
|
2009-02-16 17:32:30 -07:00
|
|
|
r.lock.Lock();
|
|
|
|
defer r.lock.Unlock();
|
|
|
|
|
2009-05-22 23:43:57 -06:00
|
|
|
return r.p.CloseReader();
|
2009-02-16 17:32:30 -07:00
|
|
|
}
|
|
|
|
|
2009-05-22 23:43:57 -06:00
|
|
|
func (r *pipeRead) finish() {
|
2009-02-16 17:32:30 -07:00
|
|
|
r.Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write half of pipe.
|
2009-05-22 23:43:57 -06:00
|
|
|
type pipeWrite struct {
|
2009-02-16 17:32:30 -07:00
|
|
|
lock sync.Mutex;
|
|
|
|
p *pipe;
|
|
|
|
}
|
|
|
|
|
2009-05-22 23:43:57 -06:00
|
|
|
func (w *pipeWrite) Write(data []byte) (n int, err os.Error) {
|
2009-02-16 17:32:30 -07:00
|
|
|
w.lock.Lock();
|
|
|
|
defer w.lock.Unlock();
|
|
|
|
|
|
|
|
return w.p.Write(data);
|
|
|
|
}
|
|
|
|
|
2009-05-22 23:43:57 -06:00
|
|
|
func (w *pipeWrite) Close() os.Error {
|
2009-02-16 17:32:30 -07:00
|
|
|
w.lock.Lock();
|
|
|
|
defer w.lock.Unlock();
|
|
|
|
|
2009-05-22 23:43:57 -06:00
|
|
|
return w.p.CloseWriter();
|
2009-02-16 17:32:30 -07:00
|
|
|
}
|
|
|
|
|
2009-05-22 23:43:57 -06:00
|
|
|
func (w *pipeWrite) finish() {
|
2009-02-16 17:32:30 -07:00
|
|
|
w.Close();
|
|
|
|
}
|
|
|
|
|
2009-03-06 04:43:44 -07:00
|
|
|
// Pipe creates a synchronous in-memory pipe.
|
2009-05-22 23:43:57 -06:00
|
|
|
// Used to connect code expecting an io.Reader
|
2009-05-08 12:22:57 -06:00
|
|
|
// with code expecting an io.Writer.
|
2009-05-22 23:43:57 -06:00
|
|
|
//
|
|
|
|
// Reads on one end are matched by writes on the other.
|
|
|
|
// Writes don't complete until all the data has been
|
|
|
|
// written or the read end is closed. Reads return
|
|
|
|
// any available data or block until the next write
|
|
|
|
// or the write end is closed.
|
|
|
|
func Pipe() (io.ReadCloser, io.WriteCloser) {
|
2009-02-16 17:32:30 -07:00
|
|
|
p := new(pipe);
|
|
|
|
p.cr = make(chan []byte, 1);
|
|
|
|
p.cw = make(chan pipeReturn, 1);
|
2009-05-22 23:43:57 -06:00
|
|
|
r := new(pipeRead);
|
2009-02-16 17:32:30 -07:00
|
|
|
r.p = p;
|
2009-05-22 23:43:57 -06:00
|
|
|
w := new(pipeWrite);
|
2009-02-16 17:32:30 -07:00
|
|
|
w.p = p;
|
|
|
|
return r, w;
|
|
|
|
}
|
|
|
|
|