Russ Cox | 78906c3 | 2009-02-16 16:32:30 -0800 | [diff] [blame] | 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 | |
Russ Cox | 2a5d30f | 2010-02-01 17:43:15 -0800 | [diff] [blame] | 5 | // Pipe adapter to connect code expecting an io.Reader |
| 6 | // with code expecting an io.Writer. |
Russ Cox | 78906c3 | 2009-02-16 16:32:30 -0800 | [diff] [blame] | 7 | |
| 8 | package io |
| 9 | |
Rob Pike | 929203a | 2012-02-06 15:09:50 +1100 | [diff] [blame] | 10 | import ( |
| 11 | "errors" |
| 12 | "sync" |
| 13 | ) |
Russ Cox | c06cf03 | 2011-11-01 21:48:52 -0400 | [diff] [blame] | 14 | |
| 15 | // ErrClosedPipe is the error used for read or write operations on a closed pipe. |
Rob Pike | 929203a | 2012-02-06 15:09:50 +1100 | [diff] [blame] | 16 | var ErrClosedPipe = errors.New("io: read/write on closed pipe") |
Russ Cox | 78906c3 | 2009-02-16 16:32:30 -0800 | [diff] [blame] | 17 | |
Russ Cox | cc62bed | 2010-04-27 10:17:17 -0700 | [diff] [blame] | 18 | type pipeResult struct { |
| 19 | n int |
Russ Cox | c06cf03 | 2011-11-01 21:48:52 -0400 | [diff] [blame] | 20 | err error |
Russ Cox | cc62bed | 2010-04-27 10:17:17 -0700 | [diff] [blame] | 21 | } |
| 22 | |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 23 | // A pipe is the shared pipe structure underlying PipeReader and PipeWriter. |
Russ Cox | 78906c3 | 2009-02-16 16:32:30 -0800 | [diff] [blame] | 24 | type pipe struct { |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 25 | rl sync.Mutex // gates readers one at a time |
| 26 | wl sync.Mutex // gates writers one at a time |
| 27 | l sync.Mutex // protects remaining fields |
| 28 | data []byte // data remaining in pending write |
| 29 | rwait sync.Cond // waiting reader |
| 30 | wwait sync.Cond // waiting writer |
Russ Cox | c06cf03 | 2011-11-01 21:48:52 -0400 | [diff] [blame] | 31 | rerr error // if reader closed, error to give writes |
| 32 | werr error // if writer closed, error to give reads |
Russ Cox | 78906c3 | 2009-02-16 16:32:30 -0800 | [diff] [blame] | 33 | } |
| 34 | |
Russ Cox | c06cf03 | 2011-11-01 21:48:52 -0400 | [diff] [blame] | 35 | func (p *pipe) read(b []byte) (n int, err error) { |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 36 | // One reader at a time. |
| 37 | p.rl.Lock() |
| 38 | defer p.rl.Unlock() |
Russ Cox | 78906c3 | 2009-02-16 16:32:30 -0800 | [diff] [blame] | 39 | |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 40 | p.l.Lock() |
| 41 | defer p.l.Unlock() |
Russ Cox | cc62bed | 2010-04-27 10:17:17 -0700 | [diff] [blame] | 42 | for { |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 43 | if p.rerr != nil { |
Russ Cox | c06cf03 | 2011-11-01 21:48:52 -0400 | [diff] [blame] | 44 | return 0, ErrClosedPipe |
Russ Cox | 78906c3 | 2009-02-16 16:32:30 -0800 | [diff] [blame] | 45 | } |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 46 | if p.data != nil { |
| 47 | break |
Russ Cox | 78906c3 | 2009-02-16 16:32:30 -0800 | [diff] [blame] | 48 | } |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 49 | if p.werr != nil { |
| 50 | return 0, p.werr |
| 51 | } |
| 52 | p.rwait.Wait() |
Russ Cox | 78906c3 | 2009-02-16 16:32:30 -0800 | [diff] [blame] | 53 | } |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 54 | n = copy(b, p.data) |
| 55 | p.data = p.data[n:] |
| 56 | if len(p.data) == 0 { |
| 57 | p.data = nil |
| 58 | p.wwait.Signal() |
Russ Cox | cc62bed | 2010-04-27 10:17:17 -0700 | [diff] [blame] | 59 | } |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 60 | return |
Russ Cox | cc62bed | 2010-04-27 10:17:17 -0700 | [diff] [blame] | 61 | } |
| 62 | |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 63 | var zero [0]byte |
| 64 | |
Russ Cox | c06cf03 | 2011-11-01 21:48:52 -0400 | [diff] [blame] | 65 | func (p *pipe) write(b []byte) (n int, err error) { |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 66 | // pipe uses nil to mean not available |
| 67 | if b == nil { |
| 68 | b = zero[:] |
Russ Cox | cc62bed | 2010-04-27 10:17:17 -0700 | [diff] [blame] | 69 | } |
Russ Cox | cc62bed | 2010-04-27 10:17:17 -0700 | [diff] [blame] | 70 | |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 71 | // One writer at a time. |
| 72 | p.wl.Lock() |
| 73 | defer p.wl.Unlock() |
Russ Cox | cc62bed | 2010-04-27 10:17:17 -0700 | [diff] [blame] | 74 | |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 75 | p.l.Lock() |
| 76 | defer p.l.Unlock() |
Rick Arnold | 4be9385 | 2013-08-13 11:04:09 -0700 | [diff] [blame] | 77 | if p.werr != nil { |
| 78 | err = ErrClosedPipe |
| 79 | return |
| 80 | } |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 81 | p.data = b |
| 82 | p.rwait.Signal() |
| 83 | for { |
| 84 | if p.data == nil { |
| 85 | break |
| 86 | } |
| 87 | if p.rerr != nil { |
| 88 | err = p.rerr |
| 89 | break |
| 90 | } |
| 91 | if p.werr != nil { |
Russ Cox | c06cf03 | 2011-11-01 21:48:52 -0400 | [diff] [blame] | 92 | err = ErrClosedPipe |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 93 | } |
| 94 | p.wwait.Wait() |
| 95 | } |
| 96 | n = len(b) - len(p.data) |
| 97 | p.data = nil // in case of rerr or werr |
| 98 | return |
Russ Cox | cc62bed | 2010-04-27 10:17:17 -0700 | [diff] [blame] | 99 | } |
| 100 | |
Russ Cox | c06cf03 | 2011-11-01 21:48:52 -0400 | [diff] [blame] | 101 | func (p *pipe) rclose(err error) { |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 102 | if err == nil { |
Russ Cox | c06cf03 | 2011-11-01 21:48:52 -0400 | [diff] [blame] | 103 | err = ErrClosedPipe |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 104 | } |
| 105 | p.l.Lock() |
| 106 | defer p.l.Unlock() |
| 107 | p.rerr = err |
| 108 | p.rwait.Signal() |
| 109 | p.wwait.Signal() |
Russ Cox | cc62bed | 2010-04-27 10:17:17 -0700 | [diff] [blame] | 110 | } |
| 111 | |
Russ Cox | c06cf03 | 2011-11-01 21:48:52 -0400 | [diff] [blame] | 112 | func (p *pipe) wclose(err error) { |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 113 | if err == nil { |
Russ Cox | c06cf03 | 2011-11-01 21:48:52 -0400 | [diff] [blame] | 114 | err = EOF |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 115 | } |
| 116 | p.l.Lock() |
| 117 | defer p.l.Unlock() |
| 118 | p.werr = err |
| 119 | p.rwait.Signal() |
| 120 | p.wwait.Signal() |
| 121 | } |
Russ Cox | cc62bed | 2010-04-27 10:17:17 -0700 | [diff] [blame] | 122 | |
Russ Cox | 6defc25 | 2009-06-06 21:51:05 -0700 | [diff] [blame] | 123 | // A PipeReader is the read half of a pipe. |
| 124 | type PipeReader struct { |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 125 | p *pipe |
Russ Cox | 78906c3 | 2009-02-16 16:32:30 -0800 | [diff] [blame] | 126 | } |
| 127 | |
Russ Cox | 6defc25 | 2009-06-06 21:51:05 -0700 | [diff] [blame] | 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 | // If the write end is closed with an error, that error is |
Russ Cox | c06cf03 | 2011-11-01 21:48:52 -0400 | [diff] [blame] | 132 | // returned as err; otherwise err is EOF. |
| 133 | func (r *PipeReader) Read(data []byte) (n int, err error) { |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 134 | return r.p.read(data) |
Russ Cox | 78906c3 | 2009-02-16 16:32:30 -0800 | [diff] [blame] | 135 | } |
| 136 | |
Russ Cox | 6defc25 | 2009-06-06 21:51:05 -0700 | [diff] [blame] | 137 | // Close closes the reader; subsequent writes to the |
Russ Cox | c06cf03 | 2011-11-01 21:48:52 -0400 | [diff] [blame] | 138 | // write half of the pipe will return the error ErrClosedPipe. |
| 139 | func (r *PipeReader) Close() error { |
Russ Cox | cc62bed | 2010-04-27 10:17:17 -0700 | [diff] [blame] | 140 | return r.CloseWithError(nil) |
Russ Cox | 78906c3 | 2009-02-16 16:32:30 -0800 | [diff] [blame] | 141 | } |
| 142 | |
Russ Cox | 6defc25 | 2009-06-06 21:51:05 -0700 | [diff] [blame] | 143 | // CloseWithError closes the reader; subsequent writes |
Russ Cox | cc62bed | 2010-04-27 10:17:17 -0700 | [diff] [blame] | 144 | // to the write half of the pipe will return the error err. |
Russ Cox | c06cf03 | 2011-11-01 21:48:52 -0400 | [diff] [blame] | 145 | func (r *PipeReader) CloseWithError(err error) error { |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 146 | r.p.rclose(err) |
| 147 | return nil |
Russ Cox | 6defc25 | 2009-06-06 21:51:05 -0700 | [diff] [blame] | 148 | } |
| 149 | |
Russ Cox | cc62bed | 2010-04-27 10:17:17 -0700 | [diff] [blame] | 150 | // A PipeWriter is the write half of a pipe. |
Russ Cox | 6defc25 | 2009-06-06 21:51:05 -0700 | [diff] [blame] | 151 | type PipeWriter struct { |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 152 | p *pipe |
Russ Cox | 78906c3 | 2009-02-16 16:32:30 -0800 | [diff] [blame] | 153 | } |
| 154 | |
Russ Cox | 6defc25 | 2009-06-06 21:51:05 -0700 | [diff] [blame] | 155 | // Write implements the standard Write interface: |
| 156 | // it writes data to the pipe, blocking until readers |
| 157 | // have consumed all the data or the read end is closed. |
| 158 | // If the read end is closed with an error, that err is |
Russ Cox | c06cf03 | 2011-11-01 21:48:52 -0400 | [diff] [blame] | 159 | // returned as err; otherwise err is ErrClosedPipe. |
| 160 | func (w *PipeWriter) Write(data []byte) (n int, err error) { |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 161 | return w.p.write(data) |
Russ Cox | 78906c3 | 2009-02-16 16:32:30 -0800 | [diff] [blame] | 162 | } |
| 163 | |
Russ Cox | 6defc25 | 2009-06-06 21:51:05 -0700 | [diff] [blame] | 164 | // Close closes the writer; subsequent reads from the |
Russ Cox | c06cf03 | 2011-11-01 21:48:52 -0400 | [diff] [blame] | 165 | // read half of the pipe will return no bytes and EOF. |
| 166 | func (w *PipeWriter) Close() error { |
Russ Cox | cc62bed | 2010-04-27 10:17:17 -0700 | [diff] [blame] | 167 | return w.CloseWithError(nil) |
Russ Cox | 78906c3 | 2009-02-16 16:32:30 -0800 | [diff] [blame] | 168 | } |
| 169 | |
Russ Cox | 6defc25 | 2009-06-06 21:51:05 -0700 | [diff] [blame] | 170 | // CloseWithError closes the writer; subsequent reads from the |
Russ Cox | cc62bed | 2010-04-27 10:17:17 -0700 | [diff] [blame] | 171 | // read half of the pipe will return no bytes and the error err. |
Russ Cox | c06cf03 | 2011-11-01 21:48:52 -0400 | [diff] [blame] | 172 | func (w *PipeWriter) CloseWithError(err error) error { |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 173 | w.p.wclose(err) |
| 174 | return nil |
Russ Cox | 6defc25 | 2009-06-06 21:51:05 -0700 | [diff] [blame] | 175 | } |
| 176 | |
Rob Pike | 7bb335c | 2009-03-06 03:43:44 -0800 | [diff] [blame] | 177 | // Pipe creates a synchronous in-memory pipe. |
Russ Cox | 6defc25 | 2009-06-06 21:51:05 -0700 | [diff] [blame] | 178 | // It can be used to connect code expecting an io.Reader |
Rob Pike | c8b47c6 | 2009-05-08 11:22:57 -0700 | [diff] [blame] | 179 | // with code expecting an io.Writer. |
Russ Cox | 6defc25 | 2009-06-06 21:51:05 -0700 | [diff] [blame] | 180 | // Reads on one end are matched with writes on the other, |
| 181 | // copying data directly between the two; there is no internal buffering. |
Rob Pike | 5a5279e | 2012-03-01 11:24:13 +1100 | [diff] [blame] | 182 | // It is safe to call Read and Write in parallel with each other or with |
| 183 | // Close. Close will complete once pending I/O is done. Parallel calls to |
| 184 | // Read, and parallel calls to Write, are also safe: |
Robert Griesemer | de7361b | 2012-03-02 11:15:45 -0800 | [diff] [blame] | 185 | // the individual calls will be gated sequentially. |
Russ Cox | 6defc25 | 2009-06-06 21:51:05 -0700 | [diff] [blame] | 186 | func Pipe() (*PipeReader, *PipeWriter) { |
Russ Cox | 6d6f338 | 2011-03-07 10:37:28 -0500 | [diff] [blame] | 187 | p := new(pipe) |
| 188 | p.rwait.L = &p.l |
| 189 | p.wwait.L = &p.l |
| 190 | r := &PipeReader{p} |
| 191 | w := &PipeWriter{p} |
Russ Cox | cc62bed | 2010-04-27 10:17:17 -0700 | [diff] [blame] | 192 | return r, w |
Russ Cox | 78906c3 | 2009-02-16 16:32:30 -0800 | [diff] [blame] | 193 | } |