gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

gotrack.go (3160B)


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