github.com/searKing/golang/go@v1.2.117/runtime/goroutine/id.go (about) 1 // Copyright 2020 The searKing Author. 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 package goroutine 6 7 import ( 8 "bytes" 9 "errors" 10 "fmt" 11 "runtime" 12 "strconv" 13 "sync" 14 ) 15 16 var goroutineSpace = []byte("goroutine ") 17 18 // ID returns goroutine id of the goroutine that calls it. 19 // It calls runtime.Stack with a large enough buffer to capture the entire trace. 20 func ID() uint64 { 21 bp := littleBuf.Get().(*[]byte) 22 defer littleBuf.Put(bp) 23 b := *bp 24 b = b[:runtime.Stack(b, false)] 25 // Parse the 4707 out of "goroutine 4707 [" 26 b = bytes.TrimPrefix(b, goroutineSpace) 27 i := bytes.IndexByte(b, ' ') 28 if i < 0 { 29 panic(fmt.Sprintf("No space found in %q", b)) 30 } 31 b = b[:i] 32 n, err := parseUintBytes(b, 10, 64) 33 if err != nil { 34 panic(fmt.Sprintf("Failed to parse goroutine ID out of %q: %v", b, err)) 35 } 36 return n 37 } 38 39 var littleBuf = sync.Pool{ 40 New: func() any { 41 buf := make([]byte, 64) 42 return &buf 43 }, 44 } 45 46 // parseUintBytes is like strconv.ParseUint, but using a []byte. 47 func parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) { 48 var cutoff, maxVal uint64 49 50 if bitSize == 0 { 51 bitSize = int(strconv.IntSize) 52 } 53 54 s0 := s 55 switch { 56 case len(s) < 1: 57 err = strconv.ErrSyntax 58 goto Error 59 60 case 2 <= base && base <= 36: 61 // valid base; nothing to do 62 63 case base == 0: 64 // Look for octal, hex prefix. 65 switch { 66 case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'): 67 base = 16 68 s = s[2:] 69 if len(s) < 1 { 70 err = strconv.ErrSyntax 71 goto Error 72 } 73 case s[0] == '0': 74 base = 8 75 default: 76 base = 10 77 } 78 79 default: 80 err = errors.New("invalid base " + strconv.Itoa(base)) 81 goto Error 82 } 83 84 n = 0 85 cutoff = cutoff64(base) 86 maxVal = 1<<uint(bitSize) - 1 87 88 for i := 0; i < len(s); i++ { 89 var v byte 90 d := s[i] 91 switch { 92 case '0' <= d && d <= '9': 93 v = d - '0' 94 case 'a' <= d && d <= 'z': 95 v = d - 'a' + 10 96 case 'A' <= d && d <= 'Z': 97 v = d - 'A' + 10 98 default: 99 n = 0 100 err = strconv.ErrSyntax 101 goto Error 102 } 103 if int(v) >= base { 104 n = 0 105 err = strconv.ErrSyntax 106 goto Error 107 } 108 109 if n >= cutoff { 110 // n*base overflows 111 n = 1<<64 - 1 112 err = strconv.ErrRange 113 goto Error 114 } 115 n *= uint64(base) 116 117 n1 := n + uint64(v) 118 if n1 < n || n1 > maxVal { 119 // n+v overflows 120 n = 1<<64 - 1 121 err = strconv.ErrRange 122 goto Error 123 } 124 n = n1 125 } 126 127 return n, nil 128 129 Error: 130 return n, &strconv.NumError{Func: "ParseUint", Num: string(s0), Err: err} 131 } 132 133 // Return the first number n such that n*base >= 1<<64. 134 func cutoff64(base int) uint64 { 135 if base < 2 { 136 return 0 137 } 138 return (1<<64-1)/uint64(base) + 1 139 }