github.com/technosophos/deis@v1.7.1-0.20150915173815-f9005256004b/Godeps/_workspace/src/golang.org/x/crypto/ssh/buffer.go (about) 1 // Copyright 2012 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 5 package ssh 6 7 import ( 8 "io" 9 "sync" 10 ) 11 12 // buffer provides a linked list buffer for data exchange 13 // between producer and consumer. Theoretically the buffer is 14 // of unlimited capacity as it does no allocation of its own. 15 type buffer struct { 16 // protects concurrent access to head, tail and closed 17 *sync.Cond 18 19 head *element // the buffer that will be read first 20 tail *element // the buffer that will be read last 21 22 closed bool 23 } 24 25 // An element represents a single link in a linked list. 26 type element struct { 27 buf []byte 28 next *element 29 } 30 31 // newBuffer returns an empty buffer that is not closed. 32 func newBuffer() *buffer { 33 e := new(element) 34 b := &buffer{ 35 Cond: newCond(), 36 head: e, 37 tail: e, 38 } 39 return b 40 } 41 42 // write makes buf available for Read to receive. 43 // buf must not be modified after the call to write. 44 func (b *buffer) write(buf []byte) { 45 b.Cond.L.Lock() 46 e := &element{buf: buf} 47 b.tail.next = e 48 b.tail = e 49 b.Cond.Signal() 50 b.Cond.L.Unlock() 51 } 52 53 // eof closes the buffer. Reads from the buffer once all 54 // the data has been consumed will receive os.EOF. 55 func (b *buffer) eof() error { 56 b.Cond.L.Lock() 57 b.closed = true 58 b.Cond.Signal() 59 b.Cond.L.Unlock() 60 return nil 61 } 62 63 // Read reads data from the internal buffer in buf. Reads will block 64 // if no data is available, or until the buffer is closed. 65 func (b *buffer) Read(buf []byte) (n int, err error) { 66 b.Cond.L.Lock() 67 defer b.Cond.L.Unlock() 68 69 for len(buf) > 0 { 70 // if there is data in b.head, copy it 71 if len(b.head.buf) > 0 { 72 r := copy(buf, b.head.buf) 73 buf, b.head.buf = buf[r:], b.head.buf[r:] 74 n += r 75 continue 76 } 77 // if there is a next buffer, make it the head 78 if len(b.head.buf) == 0 && b.head != b.tail { 79 b.head = b.head.next 80 continue 81 } 82 83 // if at least one byte has been copied, return 84 if n > 0 { 85 break 86 } 87 88 // if nothing was read, and there is nothing outstanding 89 // check to see if the buffer is closed. 90 if b.closed { 91 err = io.EOF 92 break 93 } 94 // out of buffers, wait for producer 95 b.Cond.Wait() 96 } 97 return 98 }