github.com/coreos/mantle@v0.13.0/lang/bufpipe/pipe.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 // Licensed under the same terms as Go itself: 5 // https://github.com/golang/go/blob/master/LICENSE 6 7 // Pipe adapter to connect code expecting an io.Reader 8 // with code expecting an io.Writer. 9 10 package bufpipe 11 12 import ( 13 "bytes" 14 "io" 15 "sync" 16 ) 17 18 // A pipe is the shared pipe structure underlying PipeReader and PipeWriter. 19 type pipe struct { 20 rl sync.Mutex // gates readers one at a time 21 wl sync.Mutex // gates writers one at a time 22 l sync.Mutex // protects remaining fields 23 buf pipeBuffer // data buffer 24 rwait sync.Cond // waiting reader 25 wwait sync.Cond // waiting writer 26 rerr error // if reader closed, error to give writes 27 werr error // if writer closed, error to give reads 28 } 29 30 type pipeBuffer interface { 31 Len() int 32 io.Writer 33 io.Reader 34 } 35 36 func newPipe(buf pipeBuffer) *pipe { 37 p := &pipe{buf: buf} 38 p.rwait.L = &p.l 39 p.wwait.L = &p.l 40 return p 41 } 42 43 func (p *pipe) read(b []byte) (n int, err error) { 44 // One reader at a time. 45 p.rl.Lock() 46 defer p.rl.Unlock() 47 48 p.l.Lock() 49 defer p.l.Unlock() 50 for { 51 if p.rerr != nil { 52 return 0, io.ErrClosedPipe 53 } 54 if p.buf.Len() > 0 { 55 break 56 } 57 if p.werr != nil { 58 return 0, p.werr 59 } 60 p.rwait.Wait() 61 } 62 n, err = p.buf.Read(b) 63 p.wwait.Signal() 64 return 65 } 66 67 var zero [0]byte 68 69 func (p *pipe) write(b []byte) (n int, err error) { 70 // pipe uses nil to mean not available 71 if b == nil { 72 b = zero[:] 73 } 74 75 // One writer at a time. 76 p.wl.Lock() 77 defer p.wl.Unlock() 78 79 p.l.Lock() 80 defer p.l.Unlock() 81 for { 82 if p.werr != nil { 83 err = io.ErrClosedPipe 84 break 85 } 86 if p.rerr != nil { 87 err = p.rerr 88 break 89 } 90 nn, err := p.buf.Write(b[n:]) 91 p.rwait.Signal() 92 n += nn 93 if err != errWriteFull { 94 break 95 } 96 p.wwait.Wait() 97 } 98 return 99 } 100 101 func (p *pipe) rclose(err error) { 102 if err == nil { 103 err = io.ErrClosedPipe 104 } 105 p.l.Lock() 106 defer p.l.Unlock() 107 p.rerr = err 108 p.rwait.Signal() 109 p.wwait.Signal() 110 } 111 112 func (p *pipe) wclose(err error) { 113 if err == nil { 114 err = io.EOF 115 } 116 p.l.Lock() 117 defer p.l.Unlock() 118 p.werr = err 119 p.rwait.Signal() 120 p.wwait.Signal() 121 } 122 123 // A PipeReader is the read half of a pipe. 124 type PipeReader struct { 125 p *pipe 126 } 127 128 // Read implements the standard Read interface: 129 // it reads data from the pipe, blocking until a writer 130 // arrives or the write end is closed. 131 // Closing the write end does not prevent reading buffered data. 132 // If the write end is closed with an error, that error is 133 // returned as err; otherwise err is io.EOF. 134 func (r *PipeReader) Read(data []byte) (n int, err error) { 135 return r.p.read(data) 136 } 137 138 // Close closes the reader; subsequent writes to the 139 // write half of the pipe will return the error io.ErrClosedPipe. 140 func (r *PipeReader) Close() error { 141 return r.CloseWithError(nil) 142 } 143 144 // CloseWithError closes the reader; subsequent writes 145 // to the write half of the pipe will return the error err. 146 func (r *PipeReader) CloseWithError(err error) error { 147 r.p.rclose(err) 148 return nil 149 } 150 151 // A PipeWriter is the write half of a pipe. 152 type PipeWriter struct { 153 p *pipe 154 } 155 156 // Write implements the standard Write interface: 157 // it writes data to the pipe, returning once the data is 158 // buffered or the read end is closed. 159 // When using a FixedPipe, Write may block until one 160 // or more readers have consumed some of the data. 161 // If the read end is closed with an error, that err is 162 // returned as err; otherwise err is io.ErrClosedPipe. 163 func (w *PipeWriter) Write(data []byte) (n int, err error) { 164 return w.p.write(data) 165 } 166 167 // Close closes the writer. 168 // Buffered data may still be read. 169 // Once the buffer is empty subsequent reads from the 170 // read half of the pipe will return no bytes and io.EOF. 171 func (w *PipeWriter) Close() error { 172 return w.CloseWithError(nil) 173 } 174 175 // CloseWithError closes the writer. 176 // Buffered data may still be read. 177 // Once the buffer is empty subsequent reads from the 178 // read half of the pipe will return no bytes and the error err, 179 // or io.EOF if err is nil. 180 // 181 // CloseWithError always returns nil. 182 func (w *PipeWriter) CloseWithError(err error) error { 183 w.p.wclose(err) 184 return nil 185 } 186 187 // Pipe creates a synchronous in-memory pipe with an unlimited buffer. 188 // If the input size is unknown a FixedPipe may be preferable. 189 // 190 // Reads will block until data is written. 191 // Writes will never block. 192 // 193 // It is safe to call Read and Write in parallel with each other or with Close. 194 // Parallel calls to Read and parallel calls to Write are also safe: 195 // the individual calls will be gated sequentially. 196 func Pipe() (*PipeReader, *PipeWriter) { 197 p := newPipe(&bytes.Buffer{}) 198 r := &PipeReader{p} 199 w := &PipeWriter{p} 200 return r, w 201 } 202 203 const minBufferSize = 16 204 205 // FixedPipe creates a synchronous in-memory pipe with a 206 // fixed-size buffer that has at least the specified size. 207 // It can be used to mimic a kernel provided fifo or socket 208 // which have an internal buffer and blocking I/O. 209 // 210 // Reads will block until data is written. 211 // Writes will block when the internal buffer is filled. 212 // 213 // It is safe to call Read and Write in parallel with each other or with Close. 214 // Parallel calls to Read and parallel calls to Write are also safe: 215 // the individual calls will be gated sequentially. 216 func FixedPipe(size int) (*PipeReader, *PipeWriter) { 217 if size < minBufferSize { 218 size = minBufferSize 219 } 220 p := newPipe(&fixedBuffer{buf: make([]byte, size)}) 221 r := &PipeReader{p} 222 w := &PipeWriter{p} 223 return r, w 224 }