http.go 2.8 KB

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