github.com/kaydxh/golang@v0.0.131/go/runtime/goroutine.go (about)

     1  /*
     2   *Copyright (c) 2022, kaydxh
     3   *
     4   *Permission is hereby granted, free of charge, to any person obtaining a copy
     5   *of this software and associated documentation files (the "Software"), to deal
     6   *in the Software without restriction, including without limitation the rights
     7   *to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     8   *copies of the Software, and to permit persons to whom the Software is
     9   *furnished to do so, subject to the following conditions:
    10   *
    11   *The above copyright notice and this permission notice shall be included in all
    12   *copies or substantial portions of the Software.
    13   *
    14   *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15   *IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16   *FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17   *AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18   *LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19   *OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    20   *SOFTWARE.
    21   */
    22  package runtime
    23  
    24  import (
    25  	"bytes"
    26  	"errors"
    27  	"fmt"
    28  	"runtime"
    29  	"strconv"
    30  	"sync"
    31  )
    32  
    33  var goroutineSpace = []byte("goroutine ")
    34  
    35  //low performance
    36  func GoroutineID() uint64 {
    37  	bp := littleBuf.Get().(*[]byte)
    38  	defer littleBuf.Put(bp)
    39  	b := *bp
    40  	b = b[:runtime.Stack(b, false)]
    41  	// Parse the 4707 out of "goroutine 4707 ["
    42  	b = bytes.TrimPrefix(b, goroutineSpace)
    43  	i := bytes.IndexByte(b, ' ')
    44  	if i < 0 {
    45  		panic(fmt.Sprintf("No space found in %q", b))
    46  	}
    47  	b = b[:i]
    48  	n, err := parseUintBytes(b, 10, 64)
    49  	if err != nil {
    50  		panic(fmt.Sprintf("Failed to parse goroutine ID out of %q: %v", b, err))
    51  	}
    52  	return n
    53  }
    54  
    55  var littleBuf = sync.Pool{
    56  	New: func() interface{} {
    57  		buf := make([]byte, 64)
    58  		return &buf
    59  	},
    60  }
    61  
    62  // parseUintBytes is like strconv.ParseUint, but using a []byte.
    63  func parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) {
    64  	var cutoff, maxVal uint64
    65  
    66  	if bitSize == 0 {
    67  		bitSize = int(strconv.IntSize)
    68  	}
    69  
    70  	s0 := s
    71  	switch {
    72  	case len(s) < 1:
    73  		err = strconv.ErrSyntax
    74  		goto Error
    75  
    76  	case 2 <= base && base <= 36:
    77  		// valid base; nothing to do
    78  
    79  	case base == 0:
    80  		// Look for octal, hex prefix.
    81  		switch {
    82  		case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
    83  			base = 16
    84  			s = s[2:]
    85  			if len(s) < 1 {
    86  				err = strconv.ErrSyntax
    87  				goto Error
    88  			}
    89  		case s[0] == '0':
    90  			base = 8
    91  		default:
    92  			base = 10
    93  		}
    94  
    95  	default:
    96  		err = errors.New("invalid base " + strconv.Itoa(base))
    97  		goto Error
    98  	}
    99  
   100  	n = 0
   101  	cutoff = cutoff64(base)
   102  	maxVal = 1<<uint(bitSize) - 1
   103  
   104  	for i := 0; i < len(s); i++ {
   105  		var v byte
   106  		d := s[i]
   107  		switch {
   108  		case '0' <= d && d <= '9':
   109  			v = d - '0'
   110  		case 'a' <= d && d <= 'z':
   111  			v = d - 'a' + 10
   112  		case 'A' <= d && d <= 'Z':
   113  			v = d - 'A' + 10
   114  		default:
   115  			n = 0
   116  			err = strconv.ErrSyntax
   117  			goto Error
   118  		}
   119  		if int(v) >= base {
   120  			n = 0
   121  			err = strconv.ErrSyntax
   122  			goto Error
   123  		}
   124  
   125  		if n >= cutoff {
   126  			// n*base overflows
   127  			n = 1<<64 - 1
   128  			err = strconv.ErrRange
   129  			goto Error
   130  		}
   131  		n *= uint64(base)
   132  
   133  		n1 := n + uint64(v)
   134  		if n1 < n || n1 > maxVal {
   135  			// n+v overflows
   136  			n = 1<<64 - 1
   137  			err = strconv.ErrRange
   138  			goto Error
   139  		}
   140  		n = n1
   141  	}
   142  
   143  	return n, nil
   144  
   145  Error:
   146  	return n, &strconv.NumError{Func: "ParseUint", Num: string(s0), Err: err}
   147  }
   148  
   149  // Return the first number n such that n*base >= 1<<64.
   150  func cutoff64(base int) uint64 {
   151  	if base < 2 {
   152  		return 0
   153  	}
   154  	return (1<<64-1)/uint64(base) + 1
   155  }