Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 

154 rindas
3.6 KiB

  1. // Copyright 2014 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 http2
  5. import (
  6. "errors"
  7. "io"
  8. "sync"
  9. )
  10. // pipe is a goroutine-safe io.Reader/io.Writer pair. It's like
  11. // io.Pipe except there are no PipeReader/PipeWriter halves, and the
  12. // underlying buffer is an interface. (io.Pipe is always unbuffered)
  13. type pipe struct {
  14. mu sync.Mutex
  15. c sync.Cond // c.L lazily initialized to &p.mu
  16. b pipeBuffer
  17. err error // read error once empty. non-nil means closed.
  18. breakErr error // immediate read error (caller doesn't see rest of b)
  19. donec chan struct{} // closed on error
  20. readFn func() // optional code to run in Read before error
  21. }
  22. type pipeBuffer interface {
  23. Len() int
  24. io.Writer
  25. io.Reader
  26. }
  27. func (p *pipe) Len() int {
  28. p.mu.Lock()
  29. defer p.mu.Unlock()
  30. return p.b.Len()
  31. }
  32. // Read waits until data is available and copies bytes
  33. // from the buffer into p.
  34. func (p *pipe) Read(d []byte) (n int, err error) {
  35. p.mu.Lock()
  36. defer p.mu.Unlock()
  37. if p.c.L == nil {
  38. p.c.L = &p.mu
  39. }
  40. for {
  41. if p.breakErr != nil {
  42. return 0, p.breakErr
  43. }
  44. if p.b.Len() > 0 {
  45. return p.b.Read(d)
  46. }
  47. if p.err != nil {
  48. if p.readFn != nil {
  49. p.readFn() // e.g. copy trailers
  50. p.readFn = nil // not sticky like p.err
  51. }
  52. return 0, p.err
  53. }
  54. p.c.Wait()
  55. }
  56. }
  57. var errClosedPipeWrite = errors.New("write on closed buffer")
  58. // Write copies bytes from p into the buffer and wakes a reader.
  59. // It is an error to write more data than the buffer can hold.
  60. func (p *pipe) Write(d []byte) (n int, err error) {
  61. p.mu.Lock()
  62. defer p.mu.Unlock()
  63. if p.c.L == nil {
  64. p.c.L = &p.mu
  65. }
  66. defer p.c.Signal()
  67. if p.err != nil {
  68. return 0, errClosedPipeWrite
  69. }
  70. return p.b.Write(d)
  71. }
  72. // CloseWithError causes the next Read (waking up a current blocked
  73. // Read if needed) to return the provided err after all data has been
  74. // read.
  75. //
  76. // The error must be non-nil.
  77. func (p *pipe) CloseWithError(err error) { p.closeWithError(&p.err, err, nil) }
  78. // BreakWithError causes the next Read (waking up a current blocked
  79. // Read if needed) to return the provided err immediately, without
  80. // waiting for unread data.
  81. func (p *pipe) BreakWithError(err error) { p.closeWithError(&p.breakErr, err, nil) }
  82. // closeWithErrorAndCode is like CloseWithError but also sets some code to run
  83. // in the caller's goroutine before returning the error.
  84. func (p *pipe) closeWithErrorAndCode(err error, fn func()) { p.closeWithError(&p.err, err, fn) }
  85. func (p *pipe) closeWithError(dst *error, err error, fn func()) {
  86. if err == nil {
  87. panic("err must be non-nil")
  88. }
  89. p.mu.Lock()
  90. defer p.mu.Unlock()
  91. if p.c.L == nil {
  92. p.c.L = &p.mu
  93. }
  94. defer p.c.Signal()
  95. if *dst != nil {
  96. // Already been done.
  97. return
  98. }
  99. p.readFn = fn
  100. *dst = err
  101. p.closeDoneLocked()
  102. }
  103. // requires p.mu be held.
  104. func (p *pipe) closeDoneLocked() {
  105. if p.donec == nil {
  106. return
  107. }
  108. // Close if unclosed. This isn't racy since we always
  109. // hold p.mu while closing.
  110. select {
  111. case <-p.donec:
  112. default:
  113. close(p.donec)
  114. }
  115. }
  116. // Err returns the error (if any) first set by BreakWithError or CloseWithError.
  117. func (p *pipe) Err() error {
  118. p.mu.Lock()
  119. defer p.mu.Unlock()
  120. if p.breakErr != nil {
  121. return p.breakErr
  122. }
  123. return p.err
  124. }
  125. // Done returns a channel which is closed if and when this pipe is closed
  126. // with CloseWithError.
  127. func (p *pipe) Done() <-chan struct{} {
  128. p.mu.Lock()
  129. defer p.mu.Unlock()
  130. if p.donec == nil {
  131. p.donec = make(chan struct{})
  132. if p.err != nil || p.breakErr != nil {
  133. // Already hit an error.
  134. p.closeDoneLocked()
  135. }
  136. }
  137. return p.donec
  138. }