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.
5 // Defensive debug-only utility to track that functions run on the
6 // goroutine that they're supposed to.
20 var DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"
22 type goroutineLock uint64
24 func newGoroutineLock() goroutineLock {
28 return goroutineLock(curGoroutineID())
31 func (g goroutineLock) check() {
35 if curGoroutineID() != uint64(g) {
36 panic("running on the wrong goroutine")
40 func (g goroutineLock) checkNotOn() {
44 if curGoroutineID() == uint64(g) {
45 panic("running on the wrong goroutine")
49 var goroutineSpace = []byte("goroutine ")
51 func curGoroutineID() uint64 {
52 bp := littleBuf.Get().(*[]byte)
53 defer littleBuf.Put(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, ' ')
60 panic(fmt.Sprintf("No space found in %q", b))
63 n, err := parseUintBytes(b, 10, 64)
65 panic(fmt.Sprintf("Failed to parse goroutine ID out of %q: %v", b, err))
70 var littleBuf = sync.Pool{
71 New: func() interface{} {
72 buf := make([]byte, 64)
77 // parseUintBytes is like strconv.ParseUint, but using a []byte.
78 func parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) {
79 var cutoff, maxVal uint64
82 bitSize = int(strconv.IntSize)
88 err = strconv.ErrSyntax
91 case 2 <= base && base <= 36:
92 // valid base; nothing to do
95 // Look for octal, hex prefix.
97 case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
101 err = strconv.ErrSyntax
111 err = errors.New("invalid base " + strconv.Itoa(base))
116 cutoff = cutoff64(base)
117 maxVal = 1<<uint(bitSize) - 1
119 for i := 0; i < len(s); i++ {
123 case '0' <= d && d <= '9':
125 case 'a' <= d && d <= 'z':
127 case 'A' <= d && d <= 'Z':
131 err = strconv.ErrSyntax
136 err = strconv.ErrSyntax
143 err = strconv.ErrRange
149 if n1 < n || n1 > maxVal {
152 err = strconv.ErrRange
161 return n, &strconv.NumError{Func: "ParseUint", Num: string(s0), Err: err}
164 // Return the first number n such that n*base >= 1<<64.
165 func cutoff64(base int) uint64 {
169 return (1<<64-1)/uint64(base) + 1