github.com/xg0n/routine@v0.0.0-20240119033701-c364deb94aee/goid.go (about)

     1  package routine
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"unsafe"
     7  )
     8  
     9  var (
    10  	offsetGoid         uintptr
    11  	offsetParentGoid   uintptr
    12  	offsetPaniconfault uintptr
    13  	offsetGopc         uintptr
    14  	offsetLabels       uintptr
    15  )
    16  
    17  // Field names of g struct can be found at
    18  // https://github.com/golang/go/blob/go1.21.6/src/runtime/runtime2.go#L414
    19  func init() {
    20  	gt := getgt()
    21  	offsetGoid = offset(gt, "goid")
    22  	offsetParentGoid = offset(gt, "parentGoid")
    23  	offsetPaniconfault = offset(gt, "paniconfault")
    24  	offsetGopc = offset(gt, "gopc")
    25  	offsetLabels = offset(gt, "labels")
    26  }
    27  
    28  type g struct {
    29  	goid         int64
    30  	parentGoid   uint64
    31  	paniconfault *bool
    32  	gopc         *uintptr
    33  	labels       *unsafe.Pointer
    34  }
    35  
    36  //go:norace
    37  func (gp g) getPanicOnFault() bool {
    38  	return *gp.paniconfault
    39  }
    40  
    41  //go:norace
    42  func (gp g) setPanicOnFault(new bool) (old bool) {
    43  	old = *gp.paniconfault
    44  	*gp.paniconfault = new
    45  	return old
    46  }
    47  
    48  //go:norace
    49  func (gp g) getLabels() unsafe.Pointer {
    50  	return *gp.labels
    51  }
    52  
    53  //go:norace
    54  func (gp g) setLabels(labels unsafe.Pointer) {
    55  	*gp.labels = labels
    56  }
    57  
    58  // getg returns current coroutine struct.
    59  func getg() g {
    60  	gp := getgp()
    61  	if gp == nil {
    62  		panic("Failed to get gp from runtime natively.")
    63  	}
    64  	return g{
    65  		goid:         *(*int64)(add(gp, offsetGoid)),
    66  		parentGoid:   *(*uint64)(add(gp, offsetParentGoid)),
    67  		paniconfault: (*bool)(add(gp, offsetPaniconfault)),
    68  		gopc:         (*uintptr)(add(gp, offsetGopc)),
    69  		labels:       (*unsafe.Pointer)(add(gp, offsetLabels)),
    70  	}
    71  }
    72  
    73  // offset returns the offset of the specified field.
    74  func offset(t reflect.Type, f string) uintptr {
    75  	field, found := t.FieldByName(f)
    76  	if found {
    77  		return field.Offset
    78  	}
    79  	panic(fmt.Sprintf("No such field '%v' of struct '%v.%v'.", f, t.PkgPath(), t.Name()))
    80  }
    81  
    82  // add pointer addition operation.
    83  func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
    84  	return unsafe.Pointer(uintptr(p) + x)
    85  }