github.com/liangmanlin/routine@v1.1.0/thread.go (about)

     1  package routine
     2  
     3  import (
     4  	"runtime"
     5  	"unsafe"
     6  )
     7  
     8  const threadMagic = int64('r')<<48 |
     9  	int64('o')<<40 |
    10  	int64('u')<<32 |
    11  	int64('t')<<24 |
    12  	int64('i')<<16 |
    13  	int64('n')<<8 |
    14  	int64('e')
    15  
    16  type thread struct {
    17  	labels map[string]string //pprof
    18  	magic  int64             //mark
    19  	id     int64             //goid
    20  	val    unsafe.Pointer
    21  }
    22  
    23  // currentThread returns a pointer to the currently executing goroutine's thread struct.
    24  //go:norace
    25  //go:nocheckptr
    26  func currentThread(create bool) *thread {
    27  	gp := getg()
    28  	goid := gp.goid
    29  	label := gp.getLabels()
    30  	//nothing inherited
    31  	if label == nil {
    32  		if create {
    33  			newt := &thread{labels: nil, magic: threadMagic, id: goid}
    34  			gp.setLabels(unsafe.Pointer(newt))
    35  			runtime.SetFinalizer(newt, threadFinalize)
    36  			return newt
    37  		}
    38  		return nil
    39  	}
    40  	//inherited map then create
    41  	t, magic, id := extractThread(gp, label)
    42  	if magic != threadMagic {
    43  		if create {
    44  			mp := *(*map[string]string)(label)
    45  			newt := &thread{labels: mp, magic: threadMagic, id: goid}
    46  			gp.setLabels(unsafe.Pointer(newt))
    47  			runtime.SetFinalizer(newt, threadFinalize)
    48  			return newt
    49  		}
    50  		return nil
    51  	}
    52  	//inherited thread then recreate
    53  	if id != goid {
    54  		if create || t.labels != nil {
    55  			newt := &thread{labels: t.labels, magic: threadMagic, id: goid}
    56  			gp.setLabels(unsafe.Pointer(newt))
    57  			runtime.SetFinalizer(newt, threadFinalize)
    58  			return newt
    59  		}
    60  		gp.setLabels(nil)
    61  		return nil
    62  	}
    63  	//all is ok
    64  	return t
    65  }
    66  
    67  // extractThread extract thread from unsafe.Pointer and catch fault error.
    68  //go:norace
    69  //go:nocheckptr
    70  func extractThread(gp g, label unsafe.Pointer) (t *thread, magic int64, id int64) {
    71  	if thread_safe {
    72  		old := gp.setPanicOnFault(true)
    73  		defer func() {
    74  			gp.setPanicOnFault(old)
    75  			recover()
    76  		}()
    77  	}
    78  	t = (*thread)(label)
    79  	return t, t.magic, t.id
    80  }
    81  
    82  func threadFinalize(t *thread) {
    83  	t.magic = 0
    84  }