The reconcile package is used for DOM reconcilation in Isomorphic Go web applications.

gotrack.go 3.1KB

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