OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / net / http2 / gotrack.go
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 }