cubefs
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
5// Defensive debug-only utility to track that functions run on the
6// goroutine that they're supposed to.
7
8package http29
10import (11"bytes"12"errors"13"fmt"14"os"15"runtime"16"strconv"17"sync"18)
19
20var DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"21
22type goroutineLock uint6423
24func newGoroutineLock() goroutineLock {25if !DebugGoroutines {26return 027}28return goroutineLock(curGoroutineID())29}
30
31func (g goroutineLock) check() {32if !DebugGoroutines {33return34}35if curGoroutineID() != uint64(g) {36panic("running on the wrong goroutine")37}38}
39
40func (g goroutineLock) checkNotOn() {41if !DebugGoroutines {42return43}44if curGoroutineID() == uint64(g) {45panic("running on the wrong goroutine")46}47}
48
49var goroutineSpace = []byte("goroutine ")50
51func curGoroutineID() uint64 {52bp := littleBuf.Get().(*[]byte)53defer littleBuf.Put(bp)54b := *bp55b = b[:runtime.Stack(b, false)]56// Parse the 4707 out of "goroutine 4707 ["57b = bytes.TrimPrefix(b, goroutineSpace)58i := bytes.IndexByte(b, ' ')59if i < 0 {60panic(fmt.Sprintf("No space found in %q", b))61}62b = b[:i]63n, err := parseUintBytes(b, 10, 64)64if err != nil {65panic(fmt.Sprintf("Failed to parse goroutine ID out of %q: %v", b, err))66}67return n68}
69
70var littleBuf = sync.Pool{71New: func() interface{} {72buf := make([]byte, 64)73return &buf74},75}
76
77// parseUintBytes is like strconv.ParseUint, but using a []byte.
78func parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) {79var cutoff, maxVal uint6480
81if bitSize == 0 {82bitSize = int(strconv.IntSize)83}84
85s0 := s86switch {87case len(s) < 1:88err = strconv.ErrSyntax89goto Error90
91case 2 <= base && base <= 36:92// valid base; nothing to do93
94case base == 0:95// Look for octal, hex prefix.96switch {97case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):98base = 1699s = s[2:]100if len(s) < 1 {101err = strconv.ErrSyntax102goto Error103}104case s[0] == '0':105base = 8106default:107base = 10108}109
110default:111err = errors.New("invalid base " + strconv.Itoa(base))112goto Error113}114
115n = 0116cutoff = cutoff64(base)117maxVal = 1<<uint(bitSize) - 1118
119for i := 0; i < len(s); i++ {120var v byte121d := s[i]122switch {123case '0' <= d && d <= '9':124v = d - '0'125case 'a' <= d && d <= 'z':126v = d - 'a' + 10127case 'A' <= d && d <= 'Z':128v = d - 'A' + 10129default:130n = 0131err = strconv.ErrSyntax132goto Error133}134if int(v) >= base {135n = 0136err = strconv.ErrSyntax137goto Error138}139
140if n >= cutoff {141// n*base overflows142n = 1<<64 - 1143err = strconv.ErrRange144goto Error145}146n *= uint64(base)147
148n1 := n + uint64(v)149if n1 < n || n1 > maxVal {150// n+v overflows151n = 1<<64 - 1152err = strconv.ErrRange153goto Error154}155n = n1156}157
158return n, nil159
160Error:161return n, &strconv.NumError{Func: "ParseUint", Num: string(s0), Err: err}162}
163
164// Return the first number n such that n*base >= 1<<64.
165func cutoff64(base int) uint64 {166if base < 2 {167return 0168}169return (1<<64-1)/uint64(base) + 1170}
171