mirror of
https://github.com/kubernetes-sigs/prometheus-adapter.git
synced 2026-04-06 01:38:10 +00:00
Travis seems to be having issues pulling deps, so we'll have to check in the vendor directory and prevent the makefile from trying to regenerate it normally.
170 lines
3.1 KiB
Go
170 lines
3.1 KiB
Go
// Copyright 2014 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Defensive debug-only utility to track that functions run on the
|
|
// 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 {
|
|
if !DebugGoroutines {
|
|
return 0
|
|
}
|
|
return goroutineLock(curGoroutineID())
|
|
}
|
|
|
|
func (g goroutineLock) check() {
|
|
if !DebugGoroutines {
|
|
return
|
|
}
|
|
if curGoroutineID() != uint64(g) {
|
|
panic("running on the wrong goroutine")
|
|
}
|
|
}
|
|
|
|
func (g goroutineLock) checkNotOn() {
|
|
if !DebugGoroutines {
|
|
return
|
|
}
|
|
if curGoroutineID() == uint64(g) {
|
|
panic("running on the wrong goroutine")
|
|
}
|
|
}
|
|
|
|
var goroutineSpace = []byte("goroutine ")
|
|
|
|
func curGoroutineID() uint64 {
|
|
bp := littleBuf.Get().(*[]byte)
|
|
defer littleBuf.Put(bp)
|
|
b := *bp
|
|
b = b[:runtime.Stack(b, false)]
|
|
// Parse the 4707 out of "goroutine 4707 ["
|
|
b = bytes.TrimPrefix(b, goroutineSpace)
|
|
i := bytes.IndexByte(b, ' ')
|
|
if i < 0 {
|
|
panic(fmt.Sprintf("No space found in %q", b))
|
|
}
|
|
b = b[:i]
|
|
n, err := parseUintBytes(b, 10, 64)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("Failed to parse goroutine ID out of %q: %v", b, err))
|
|
}
|
|
return n
|
|
}
|
|
|
|
var littleBuf = sync.Pool{
|
|
New: func() interface{} {
|
|
buf := make([]byte, 64)
|
|
return &buf
|
|
},
|
|
}
|
|
|
|
// parseUintBytes is like strconv.ParseUint, but using a []byte.
|
|
func parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) {
|
|
var cutoff, maxVal uint64
|
|
|
|
if bitSize == 0 {
|
|
bitSize = int(strconv.IntSize)
|
|
}
|
|
|
|
s0 := s
|
|
switch {
|
|
case len(s) < 1:
|
|
err = strconv.ErrSyntax
|
|
goto Error
|
|
|
|
case 2 <= base && base <= 36:
|
|
// valid base; nothing to do
|
|
|
|
case base == 0:
|
|
// Look for octal, hex prefix.
|
|
switch {
|
|
case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
|
|
base = 16
|
|
s = s[2:]
|
|
if len(s) < 1 {
|
|
err = strconv.ErrSyntax
|
|
goto Error
|
|
}
|
|
case s[0] == '0':
|
|
base = 8
|
|
default:
|
|
base = 10
|
|
}
|
|
|
|
default:
|
|
err = errors.New("invalid base " + strconv.Itoa(base))
|
|
goto Error
|
|
}
|
|
|
|
n = 0
|
|
cutoff = cutoff64(base)
|
|
maxVal = 1<<uint(bitSize) - 1
|
|
|
|
for i := 0; i < len(s); i++ {
|
|
var v byte
|
|
d := s[i]
|
|
switch {
|
|
case '0' <= d && d <= '9':
|
|
v = d - '0'
|
|
case 'a' <= d && d <= 'z':
|
|
v = d - 'a' + 10
|
|
case 'A' <= d && d <= 'Z':
|
|
v = d - 'A' + 10
|
|
default:
|
|
n = 0
|
|
err = strconv.ErrSyntax
|
|
goto Error
|
|
}
|
|
if int(v) >= base {
|
|
n = 0
|
|
err = strconv.ErrSyntax
|
|
goto Error
|
|
}
|
|
|
|
if n >= cutoff {
|
|
// n*base overflows
|
|
n = 1<<64 - 1
|
|
err = strconv.ErrRange
|
|
goto Error
|
|
}
|
|
n *= uint64(base)
|
|
|
|
n1 := n + uint64(v)
|
|
if n1 < n || n1 > maxVal {
|
|
// n+v overflows
|
|
n = 1<<64 - 1
|
|
err = strconv.ErrRange
|
|
goto Error
|
|
}
|
|
n = n1
|
|
}
|
|
|
|
return n, nil
|
|
|
|
Error:
|
|
return n, &strconv.NumError{Func: "ParseUint", Num: string(s0), Err: err}
|
|
}
|
|
|
|
// Return the first number n such that n*base >= 1<<64.
|
|
func cutoff64(base int) uint64 {
|
|
if base < 2 {
|
|
return 0
|
|
}
|
|
return (1<<64-1)/uint64(base) + 1
|
|
}
|