| 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 sshimport (	"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}
 |