Something went wrong. Try again.
forked from tailscale/tailscale
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798// 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 io.EOF.func (b *buffer) eof() { b.Cond.L.Lock() b.closed = true b.Cond.Signal() b.Cond.L.Unlock()}
// 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}