forked from ebhomengo/niki
1
0
Fork 0
niki/vendor/golang.org/x/net/http2/gotrack.go

283 lines
3.2 KiB
Go
Raw Normal View History

2024-02-18 10:42:21 +00:00
// Copyright 2014 The Go Authors. All rights reserved.
2024-02-18 10:42:21 +00:00
// Use of this source code is governed by a BSD-style
2024-02-18 10:42:21 +00:00
// license that can be found in the LICENSE file.
// Defensive debug-only utility to track that functions run on the
2024-02-18 10:42:21 +00:00
// goroutine that they're supposed to.
package http2
import (
"bytes"
"errors"
"fmt"
"os"
"runtime"
"strconv"
"sync"
)
var DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"
type goroutineLock uint64
func newGoroutineLock() goroutineLock {
2024-02-18 10:42:21 +00:00
if !DebugGoroutines {
2024-02-18 10:42:21 +00:00
return 0
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return goroutineLock(curGoroutineID())
2024-02-18 10:42:21 +00:00
}
func (g goroutineLock) check() {
2024-02-18 10:42:21 +00:00
if !DebugGoroutines {
2024-02-18 10:42:21 +00:00
return
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if curGoroutineID() != uint64(g) {
2024-02-18 10:42:21 +00:00
panic("running on the wrong goroutine")
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
func (g goroutineLock) checkNotOn() {
2024-02-18 10:42:21 +00:00
if !DebugGoroutines {
2024-02-18 10:42:21 +00:00
return
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if curGoroutineID() == uint64(g) {
2024-02-18 10:42:21 +00:00
panic("running on the wrong goroutine")
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
var goroutineSpace = []byte("goroutine ")
func curGoroutineID() uint64 {
2024-02-18 10:42:21 +00:00
bp := littleBuf.Get().(*[]byte)
2024-02-18 10:42:21 +00:00
defer littleBuf.Put(bp)
2024-02-18 10:42:21 +00:00
b := *bp
2024-02-18 10:42:21 +00:00
b = b[:runtime.Stack(b, false)]
2024-02-18 10:42:21 +00:00
// Parse the 4707 out of "goroutine 4707 ["
2024-02-18 10:42:21 +00:00
b = bytes.TrimPrefix(b, goroutineSpace)
2024-02-18 10:42:21 +00:00
i := bytes.IndexByte(b, ' ')
2024-02-18 10:42:21 +00:00
if i < 0 {
2024-02-18 10:42:21 +00:00
panic(fmt.Sprintf("No space found in %q", b))
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
b = b[:i]
2024-02-18 10:42:21 +00:00
n, err := parseUintBytes(b, 10, 64)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
panic(fmt.Sprintf("Failed to parse goroutine ID out of %q: %v", b, err))
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return n
2024-02-18 10:42:21 +00:00
}
var littleBuf = sync.Pool{
2024-02-18 10:42:21 +00:00
New: func() interface{} {
2024-02-18 10:42:21 +00:00
buf := make([]byte, 64)
2024-02-18 10:42:21 +00:00
return &buf
2024-02-18 10:42:21 +00:00
},
}
// parseUintBytes is like strconv.ParseUint, but using a []byte.
2024-02-18 10:42:21 +00:00
func parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) {
2024-02-18 10:42:21 +00:00
var cutoff, maxVal uint64
if bitSize == 0 {
2024-02-18 10:42:21 +00:00
bitSize = int(strconv.IntSize)
2024-02-18 10:42:21 +00:00
}
s0 := s
2024-02-18 10:42:21 +00:00
switch {
2024-02-18 10:42:21 +00:00
case len(s) < 1:
2024-02-18 10:42:21 +00:00
err = strconv.ErrSyntax
2024-02-18 10:42:21 +00:00
goto Error
case 2 <= base && base <= 36:
2024-02-18 10:42:21 +00:00
// valid base; nothing to do
case base == 0:
2024-02-18 10:42:21 +00:00
// Look for octal, hex prefix.
2024-02-18 10:42:21 +00:00
switch {
2024-02-18 10:42:21 +00:00
case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
2024-02-18 10:42:21 +00:00
base = 16
2024-02-18 10:42:21 +00:00
s = s[2:]
2024-02-18 10:42:21 +00:00
if len(s) < 1 {
2024-02-18 10:42:21 +00:00
err = strconv.ErrSyntax
2024-02-18 10:42:21 +00:00
goto Error
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case s[0] == '0':
2024-02-18 10:42:21 +00:00
base = 8
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
base = 10
2024-02-18 10:42:21 +00:00
}
default:
2024-02-18 10:42:21 +00:00
err = errors.New("invalid base " + strconv.Itoa(base))
2024-02-18 10:42:21 +00:00
goto Error
2024-02-18 10:42:21 +00:00
}
n = 0
2024-02-18 10:42:21 +00:00
cutoff = cutoff64(base)
2024-02-18 10:42:21 +00:00
maxVal = 1<<uint(bitSize) - 1
for i := 0; i < len(s); i++ {
2024-02-18 10:42:21 +00:00
var v byte
2024-02-18 10:42:21 +00:00
d := s[i]
2024-02-18 10:42:21 +00:00
switch {
2024-02-18 10:42:21 +00:00
case '0' <= d && d <= '9':
2024-02-18 10:42:21 +00:00
v = d - '0'
2024-02-18 10:42:21 +00:00
case 'a' <= d && d <= 'z':
2024-02-18 10:42:21 +00:00
v = d - 'a' + 10
2024-02-18 10:42:21 +00:00
case 'A' <= d && d <= 'Z':
2024-02-18 10:42:21 +00:00
v = d - 'A' + 10
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
n = 0
2024-02-18 10:42:21 +00:00
err = strconv.ErrSyntax
2024-02-18 10:42:21 +00:00
goto Error
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if int(v) >= base {
2024-02-18 10:42:21 +00:00
n = 0
2024-02-18 10:42:21 +00:00
err = strconv.ErrSyntax
2024-02-18 10:42:21 +00:00
goto Error
2024-02-18 10:42:21 +00:00
}
if n >= cutoff {
2024-02-18 10:42:21 +00:00
// n*base overflows
2024-02-18 10:42:21 +00:00
n = 1<<64 - 1
2024-02-18 10:42:21 +00:00
err = strconv.ErrRange
2024-02-18 10:42:21 +00:00
goto Error
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
n *= uint64(base)
n1 := n + uint64(v)
2024-02-18 10:42:21 +00:00
if n1 < n || n1 > maxVal {
2024-02-18 10:42:21 +00:00
// n+v overflows
2024-02-18 10:42:21 +00:00
n = 1<<64 - 1
2024-02-18 10:42:21 +00:00
err = strconv.ErrRange
2024-02-18 10:42:21 +00:00
goto Error
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
n = n1
2024-02-18 10:42:21 +00:00
}
return n, nil
Error:
2024-02-18 10:42:21 +00:00
return n, &strconv.NumError{Func: "ParseUint", Num: string(s0), Err: err}
2024-02-18 10:42:21 +00:00
}
// Return the first number n such that n*base >= 1<<64.
2024-02-18 10:42:21 +00:00
func cutoff64(base int) uint64 {
2024-02-18 10:42:21 +00:00
if base < 2 {
2024-02-18 10:42:21 +00:00
return 0
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return (1<<64-1)/uint64(base) + 1
2024-02-18 10:42:21 +00:00
}