You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

99 lines
2.1 KiB

  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. package ssh
  5. import (
  6. "io"
  7. "sync"
  8. )
  9. // buffer provides a linked list buffer for data exchange
  10. // between producer and consumer. Theoretically the buffer is
  11. // of unlimited capacity as it does no allocation of its own.
  12. type buffer struct {
  13. // protects concurrent access to head, tail and closed
  14. *sync.Cond
  15. head *element // the buffer that will be read first
  16. tail *element // the buffer that will be read last
  17. closed bool
  18. }
  19. // An element represents a single link in a linked list.
  20. type element struct {
  21. buf []byte
  22. next *element
  23. }
  24. // newBuffer returns an empty buffer that is not closed.
  25. func newBuffer() *buffer {
  26. e := new(element)
  27. b := &buffer{
  28. Cond: newCond(),
  29. head: e,
  30. tail: e,
  31. }
  32. return b
  33. }
  34. // write makes buf available for Read to receive.
  35. // buf must not be modified after the call to write.
  36. func (b *buffer) write(buf []byte) {
  37. b.Cond.L.Lock()
  38. e := &element{buf: buf}
  39. b.tail.next = e
  40. b.tail = e
  41. b.Cond.Signal()
  42. b.Cond.L.Unlock()
  43. }
  44. // eof closes the buffer. Reads from the buffer once all
  45. // the data has been consumed will receive os.EOF.
  46. func (b *buffer) eof() error {
  47. b.Cond.L.Lock()
  48. b.closed = true
  49. b.Cond.Signal()
  50. b.Cond.L.Unlock()
  51. return nil
  52. }
  53. // Read reads data from the internal buffer in buf. Reads will block
  54. // if no data is available, or until the buffer is closed.
  55. func (b *buffer) Read(buf []byte) (n int, err error) {
  56. b.Cond.L.Lock()
  57. defer b.Cond.L.Unlock()
  58. for len(buf) > 0 {
  59. // if there is data in b.head, copy it
  60. if len(b.head.buf) > 0 {
  61. r := copy(buf, b.head.buf)
  62. buf, b.head.buf = buf[r:], b.head.buf[r:]
  63. n += r
  64. continue
  65. }
  66. // if there is a next buffer, make it the head
  67. if len(b.head.buf) == 0 && b.head != b.tail {
  68. b.head = b.head.next
  69. continue
  70. }
  71. // if at least one byte has been copied, return
  72. if n > 0 {
  73. break
  74. }
  75. // if nothing was read, and there is nothing outstanding
  76. // check to see if the buffer is closed.
  77. if b.closed {
  78. err = io.EOF
  79. break
  80. }
  81. // out of buffers, wait for producer
  82. b.Cond.Wait()
  83. }
  84. return
  85. }