github.com/maenmax/kairep@v0.0.0-20210218001208-55bf3df36788/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  }