github.com/smallnest/gid@v1.2.0/gid.go (about)

     1  // Copyright ©2020 Dan Kortschak. 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 gid provides functions that will return the runtime's
     6  // ID number for the calling goroutine or its creator.
     7  //
     8  // The implementation is derived from Laevus Dexter's comment in Gophers' Slack #darkarts,
     9  // https://gophers.slack.com/archives/C1C1YSQBT/p1593885226448300 post which linked to
    10  // this playground snippet https://play.golang.org/p/CSOp9wyzydP.
    11  package gid
    12  
    13  import (
    14  	"reflect"
    15  	"unsafe"
    16  )
    17  
    18  // ID returns the runtime ID of the calling goroutine.
    19  func ID() int64 {
    20  	return idOf(getg(), goidoff)
    21  }
    22  
    23  func idOf(g unsafe.Pointer, off uintptr) int64 {
    24  	return *(*int64)(add(g, off))
    25  }
    26  
    27  //go:nosplit
    28  func getg() unsafe.Pointer {
    29  	return *(*unsafe.Pointer)(add(getm(), curgoff))
    30  }
    31  
    32  //go:linkname runtime_procPin runtime.procPin
    33  func runtime_procPin() int
    34  
    35  //go:linkname runtime_procUnpin runtime.procUnpin
    36  func runtime_procUnpin() int
    37  
    38  // PID returns the "P" ID of the calling goroutine.
    39  func PID() int {
    40  	pid := runtime_procPin()
    41  	runtime_procUnpin()
    42  	return pid
    43  }
    44  
    45  //go:linkname add runtime.add
    46  //go:nosplit
    47  func add(p unsafe.Pointer, x uintptr) unsafe.Pointer
    48  
    49  //go:linkname getm runtime.getm
    50  //go:nosplit
    51  func getm() unsafe.Pointer
    52  
    53  var (
    54  	curgoff = offset("*runtime.m", "curg")
    55  	goidoff = offset("*runtime.g", "goid")
    56  )
    57  
    58  // offset returns the offset into typ for the given field.
    59  func offset(typ, field string) uintptr {
    60  	rt := toType(typesByString(typ)[0])
    61  	f, _ := rt.Elem().FieldByName(field)
    62  	return f.Offset
    63  }
    64  
    65  //go:linkname typesByString reflect.typesByString
    66  func typesByString(s string) []unsafe.Pointer
    67  
    68  //go:linkname toType reflect.toType
    69  func toType(t unsafe.Pointer) reflect.Type