github.com/suiyunonghen/DxCommonLib@v0.5.3/system/goid.go (about)

     1  //from:  https://github.com/rpccloud/goid
     2  
     3  package system
     4  
     5  import (
     6  	"github.com/suiyunonghen/DxCommonLib"
     7  	"runtime"
     8  	"strings"
     9  	"sync"
    10  	"sync/atomic"
    11  	"unsafe"
    12  )
    13  
    14  func getg() unsafe.Pointer
    15  
    16  var (
    17  	goroutinePrefix = "goroutine "
    18  	gidPos          = getGidPos()
    19  )
    20  
    21  func slowID() int64 {
    22  	buf := [32]byte{}
    23  
    24  	// Parse the 4707 out of "goroutine 4707 ["
    25  	str := strings.TrimPrefix(
    26  		string(buf[:runtime.Stack(buf[:], false)]),
    27  		goroutinePrefix,
    28  	)
    29  
    30  	if lastPos := strings.IndexByte(str, ' '); lastPos > 0 {
    31  		if id, err := DxCommonLib.ParseInt64(str[:lastPos]); err == nil {
    32  			return id
    33  		}
    34  	}
    35  	return 0
    36  }
    37  
    38  var getGidPos = func() func() int {
    39  	fnFindGidPos := func(start int) int {
    40  		if currGID, ptr := slowID(), getg(); currGID > 0 && uintptr(ptr) > 0 {
    41  			pos := start
    42  			for pos < 4096 {
    43  				if *(*int64)(unsafe.Pointer(uintptr(ptr) + uintptr(pos))) == currGID {
    44  					return pos
    45  				}
    46  				pos++
    47  			}
    48  		}
    49  		return -1
    50  	}
    51  
    52  	fnCheckPos := func(pos int) bool {
    53  		var wg sync.WaitGroup
    54  		checkCount := int32(32)
    55  		wg.Add(int(checkCount))
    56  		checkIndex := int32(0)
    57  		for i := 0; i < int(checkCount); i++ {
    58  			DxCommonLib.PostFunc(func(data ...interface{}) {
    59  				if fnFindGidPos(pos) == pos {
    60  					atomic.AddInt32(&checkIndex,1)
    61  				}
    62  				wg.Done()
    63  			})
    64  		}
    65  		wg.Wait()
    66  		return atomic.LoadInt32(&checkIndex) == checkCount
    67  	}
    68  
    69  	return func() int {
    70  		pos := fnFindGidPos(0)
    71  		for pos != -1 {
    72  			if fnCheckPos(pos) {
    73  				break
    74  			} else {
    75  				pos = fnFindGidPos(pos + 1)
    76  			}
    77  		}
    78  		return pos
    79  	}
    80  }()
    81  
    82  // GetRoutineId get current goroutine id
    83  func GetRoutineId() int64 {
    84  	if gidPos >= 0 {
    85  		return *(*int64)(unsafe.Pointer(uintptr(getg()) + uintptr(gidPos)))
    86  	}
    87  
    88  	return slowID()
    89  }