Francisco J Ballesteroszxfs put fix1449f3310 years agoHistory
98 lines · 2.1 KB · Go
RawDownload
// 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.struct buffer {	// 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.struct element {	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}