OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / golang.org / x / crypto / ssh / buffer.go
diff --git a/vendor/golang.org/x/crypto/ssh/buffer.go b/vendor/golang.org/x/crypto/ssh/buffer.go
new file mode 100644 (file)
index 0000000..6931b51
--- /dev/null
@@ -0,0 +1,98 @@
+// Copyright 2012 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.
+
+package ssh
+
+import (
+       "io"
+       "sync"
+)
+
+// buffer provides a linked list buffer for data exchange
+// between producer and consumer. Theoretically the buffer is
+// of unlimited capacity as it does no allocation of its own.
+type buffer struct {
+       // protects concurrent access to head, tail and closed
+       *sync.Cond
+
+       head *element // the buffer that will be read first
+       tail *element // the buffer that will be read last
+
+       closed bool
+}
+
+// An element represents a single link in a linked list.
+type element struct {
+       buf  []byte
+       next *element
+}
+
+// newBuffer returns an empty buffer that is not closed.
+func newBuffer() *buffer {
+       e := new(element)
+       b := &buffer{
+               Cond: newCond(),
+               head: e,
+               tail: e,
+       }
+       return b
+}
+
+// write makes buf available for Read to receive.
+// buf must not be modified after the call to write.
+func (b *buffer) write(buf []byte) {
+       b.Cond.L.Lock()
+       e := &element{buf: buf}
+       b.tail.next = e
+       b.tail = e
+       b.Cond.Signal()
+       b.Cond.L.Unlock()
+}
+
+// eof closes the buffer. Reads from the buffer once all
+// the data has been consumed will receive os.EOF.
+func (b *buffer) eof() error {
+       b.Cond.L.Lock()
+       b.closed = true
+       b.Cond.Signal()
+       b.Cond.L.Unlock()
+       return nil
+}
+
+// Read reads data from the internal buffer in buf.  Reads will block
+// if no data is available, or until the buffer is closed.
+func (b *buffer) Read(buf []byte) (n int, err error) {
+       b.Cond.L.Lock()
+       defer b.Cond.L.Unlock()
+
+       for len(buf) > 0 {
+               // if there is data in b.head, copy it
+               if len(b.head.buf) > 0 {
+                       r := copy(buf, b.head.buf)
+                       buf, b.head.buf = buf[r:], b.head.buf[r:]
+                       n += r
+                       continue
+               }
+               // if there is a next buffer, make it the head
+               if len(b.head.buf) == 0 && b.head != b.tail {
+                       b.head = b.head.next
+                       continue
+               }
+
+               // if at least one byte has been copied, return
+               if n > 0 {
+                       break
+               }
+
+               // if nothing was read, and there is nothing outstanding
+               // check to see if the buffer is closed.
+               if b.closed {
+                       err = io.EOF
+                       break
+               }
+               // out of buffers, wait for producer
+               b.Cond.Wait()
+       }
+       return
+}