gotrack.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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. // Defensive debug-only utility to track that functions run on the
  5. // goroutine that they're supposed to.
  6. package http2
  7. import (
  8. "bytes"
  9. "errors"
  10. "fmt"
  11. "os"
  12. "runtime"
  13. "strconv"
  14. "sync"
  15. "sync/atomic"
  16. )
  17. var DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"
  18. // Setting DebugGoroutines to false during a test to disable goroutine debugging
  19. // results in race detector complaints when a test leaves goroutines running before
  20. // returning. Tests shouldn't do this, of course, but when they do it generally shows
  21. // up as infrequent, hard-to-debug flakes. (See #66519.)
  22. //
  23. // Disable goroutine debugging during individual tests with an atomic bool.
  24. // (Note that it's safe to enable/disable debugging mid-test, so the actual race condition
  25. // here is harmless.)
  26. var disableDebugGoroutines atomic.Bool
  27. type goroutineLock uint64
  28. func newGoroutineLock() goroutineLock {
  29. if !DebugGoroutines || disableDebugGoroutines.Load() {
  30. return 0
  31. }
  32. return goroutineLock(curGoroutineID())
  33. }
  34. func (g goroutineLock) check() {
  35. if !DebugGoroutines || disableDebugGoroutines.Load() {
  36. return
  37. }
  38. if curGoroutineID() != uint64(g) {
  39. panic("running on the wrong goroutine")
  40. }
  41. }
  42. func (g goroutineLock) checkNotOn() {
  43. if !DebugGoroutines || disableDebugGoroutines.Load() {
  44. return
  45. }
  46. if curGoroutineID() == uint64(g) {
  47. panic("running on the wrong goroutine")
  48. }
  49. }
  50. var goroutineSpace = []byte("goroutine ")
  51. func curGoroutineID() uint64 {
  52. bp := littleBuf.Get().(*[]byte)
  53. defer littleBuf.Put(bp)
  54. b := *bp
  55. b = b[:runtime.Stack(b, false)]
  56. // Parse the 4707 out of "goroutine 4707 ["
  57. b = bytes.TrimPrefix(b, goroutineSpace)
  58. i := bytes.IndexByte(b, ' ')
  59. if i < 0 {
  60. panic(fmt.Sprintf("No space found in %q", b))
  61. }
  62. b = b[:i]
  63. n, err := parseUintBytes(b, 10, 64)
  64. if err != nil {
  65. panic(fmt.Sprintf("Failed to parse goroutine ID out of %q: %v", b, err))
  66. }
  67. return n
  68. }
  69. var littleBuf = sync.Pool{
  70. New: func() interface{} {
  71. buf := make([]byte, 64)
  72. return &buf
  73. },
  74. }
  75. // parseUintBytes is like strconv.ParseUint, but using a []byte.
  76. func parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) {
  77. var cutoff, maxVal uint64
  78. if bitSize == 0 {
  79. bitSize = int(strconv.IntSize)
  80. }
  81. s0 := s
  82. switch {
  83. case len(s) < 1:
  84. err = strconv.ErrSyntax
  85. goto Error
  86. case 2 <= base && base <= 36:
  87. // valid base; nothing to do
  88. case base == 0:
  89. // Look for octal, hex prefix.
  90. switch {
  91. case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
  92. base = 16
  93. s = s[2:]
  94. if len(s) < 1 {
  95. err = strconv.ErrSyntax
  96. goto Error
  97. }
  98. case s[0] == '0':
  99. base = 8
  100. default:
  101. base = 10
  102. }
  103. default:
  104. err = errors.New("invalid base " + strconv.Itoa(base))
  105. goto Error
  106. }
  107. n = 0
  108. cutoff = cutoff64(base)
  109. maxVal = 1<<uint(bitSize) - 1
  110. for i := 0; i < len(s); i++ {
  111. var v byte
  112. d := s[i]
  113. switch {
  114. case '0' <= d && d <= '9':
  115. v = d - '0'
  116. case 'a' <= d && d <= 'z':
  117. v = d - 'a' + 10
  118. case 'A' <= d && d <= 'Z':
  119. v = d - 'A' + 10
  120. default:
  121. n = 0
  122. err = strconv.ErrSyntax
  123. goto Error
  124. }
  125. if int(v) >= base {
  126. n = 0
  127. err = strconv.ErrSyntax
  128. goto Error
  129. }
  130. if n >= cutoff {
  131. // n*base overflows
  132. n = 1<<64 - 1
  133. err = strconv.ErrRange
  134. goto Error
  135. }
  136. n *= uint64(base)
  137. n1 := n + uint64(v)
  138. if n1 < n || n1 > maxVal {
  139. // n+v overflows
  140. n = 1<<64 - 1
  141. err = strconv.ErrRange
  142. goto Error
  143. }
  144. n = n1
  145. }
  146. return n, nil
  147. Error:
  148. return n, &strconv.NumError{Func: "ParseUint", Num: string(s0), Err: err}
  149. }
  150. // Return the first number n such that n*base >= 1<<64.
  151. func cutoff64(base int) uint64 {
  152. if base < 2 {
  153. return 0
  154. }
  155. return (1<<64-1)/uint64(base) + 1
  156. }