mirror of
https://github.com/opentffoundation/opentf.git
synced 2026-03-14 22:02:22 -04:00
* Remove `make updatedeps` from Travis build. We'll follow up with more specific plans around dependency updating in subsequent PRs. * Update all `make` targets to set `GO15VENDOREXPERIMENT=1` and to filter out `/vendor/` from `./...` where appropriate. * Temporarily remove `vet` from the `make test` target until we can figure out how to get it to not vet `vendor/`. (Initial experimentation failed to yield the proper incantation.) Everything is pinned to current master, with the exception of: * Azure/azure-sdk-for-go which is pinned before the breaking change today * aws/aws-sdk-go which is pinned to the most recent tag The documentation still needs to be updated, which we can do in a follow up PR. The goal here is to unblock release.
99 lines
2.1 KiB
Go
99 lines
2.1 KiB
Go
// 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
|
|
}
|