github.com/leromarinvit/goid@v0.0.0-20170210194639-329af3046b24/goid.go (about)

     1  // Package goid returns the current Goroutine ID.
     2  package goid
     3  
     4  import (
     5  	"reflect"
     6  	"unsafe"
     7  
     8  	"github.com/leromarinvit/typist"
     9  )
    10  
    11  //go:linkname mcall runtime.mcall
    12  func mcall(func(uintptr))
    13  
    14  //go:linkname gogo runtime.gogo
    15  func gogo(uintptr)
    16  
    17  var offsetGoid uintptr
    18  var offsetSched uintptr
    19  
    20  func init() {
    21  	pg, err := typist.TypeByString("*runtime.g")
    22  	if err != nil {
    23  		return
    24  	}
    25  	if pg.Kind() != reflect.Ptr {
    26  		return
    27  	}
    28  	g := pg.Elem()
    29  	if g.Kind() != reflect.Struct {
    30  		return
    31  	}
    32  	goid, ok := g.FieldByName("goid")
    33  	if !ok {
    34  		return
    35  	}
    36  	sched, ok := g.FieldByName("sched")
    37  	if !ok {
    38  		return
    39  	}
    40  	offsetGoid = goid.Offset
    41  	offsetSched = sched.Offset
    42  }
    43  
    44  /*
    45  Goid returns the current Goroutine ID.
    46  
    47  It relies on the Go runtime's internals, so it's your own damn fault if it eats
    48  your dog. You have been warned.
    49  
    50  BUGS: Occasionally eats your dog
    51  */
    52  func Goid() (goid int64) {
    53  	if offsetGoid == offsetSched {
    54  		return -1
    55  	}
    56  	mcall(func(g uintptr) {
    57  		id := unsafe.Pointer(g + offsetGoid)
    58  		goid = *(*int64)(id)
    59  		sched := g + offsetSched
    60  		gogo(sched)
    61  	})
    62  	return goid
    63  }