github.com/timandy/routine@v1.1.4-0.20240507073150-e4a3e1fe2ba5/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  	threadLocals            *threadLocalMap
    21  	inheritableThreadLocals *threadLocalMap
    22  }
    23  
    24  // finalize reset thread's memory.
    25  func (t *thread) finalize() {
    26  	t.labels = nil
    27  	t.magic = 0
    28  	t.id = 0
    29  	t.threadLocals = nil
    30  	t.inheritableThreadLocals = nil
    31  }
    32  
    33  // currentThread returns a pointer to the currently executing goroutine's thread struct.
    34  //
    35  //go:norace
    36  //go:nocheckptr
    37  func currentThread(create bool) *thread {
    38  	gp := getg()
    39  	goid := gp.goid
    40  	label := gp.getLabels()
    41  	//nothing inherited
    42  	if label == nil {
    43  		if create {
    44  			newt := &thread{labels: nil, magic: threadMagic, id: goid}
    45  			runtime.SetFinalizer(newt, (*thread).finalize)
    46  			gp.setLabels(unsafe.Pointer(newt))
    47  			return newt
    48  		}
    49  		return nil
    50  	}
    51  	//inherited map then create
    52  	t, magic, id := extractThread(gp, label)
    53  	if magic != threadMagic {
    54  		if create {
    55  			mp := *(*map[string]string)(label)
    56  			newt := &thread{labels: mp, magic: threadMagic, id: goid}
    57  			runtime.SetFinalizer(newt, (*thread).finalize)
    58  			gp.setLabels(unsafe.Pointer(newt))
    59  			return newt
    60  		}
    61  		return nil
    62  	}
    63  	//inherited thread then recreate
    64  	if id != goid {
    65  		if create || t.labels != nil {
    66  			newt := &thread{labels: t.labels, magic: threadMagic, id: goid}
    67  			runtime.SetFinalizer(newt, (*thread).finalize)
    68  			gp.setLabels(unsafe.Pointer(newt))
    69  			return newt
    70  		}
    71  		gp.setLabels(nil)
    72  		return nil
    73  	}
    74  	//all is ok
    75  	return t
    76  }
    77  
    78  // extractThread extract thread from unsafe.Pointer and catch fault error.
    79  //
    80  //go:norace
    81  //go:nocheckptr
    82  func extractThread(gp g, label unsafe.Pointer) (t *thread, magic int64, id int64) {
    83  	old := gp.setPanicOnFault(true)
    84  	defer func() {
    85  		gp.setPanicOnFault(old)
    86  		recover() //nolint:errcheck
    87  	}()
    88  	t = (*thread)(label)
    89  	return t, t.magic, t.id
    90  }