diff options
Diffstat (limited to 'vendor/golang.org/x/net/http2/gotrack.go')
-rw-r--r-- | vendor/golang.org/x/net/http2/gotrack.go | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/vendor/golang.org/x/net/http2/gotrack.go b/vendor/golang.org/x/net/http2/gotrack.go new file mode 100644 index 0000000..9933c9f --- /dev/null +++ b/vendor/golang.org/x/net/http2/gotrack.go | |||
@@ -0,0 +1,170 @@ | |||
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 | } | ||