gotrack.go 3.2 KB

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