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 }