github.com/isyscore/isc-gobase@v1.5.3-0.20231218061332-cbc7451899e9/goid/idapi.go (about) 1 package goid 2 3 import ( 4 "log" 5 "runtime" 6 "sync" 7 ) 8 9 const ( 10 stackSize = 1024 11 ) 12 13 var ( 14 anchor = []byte("goroutine ") 15 stackBufPool = sync.Pool{ 16 New: func() any { 17 buf := make([]byte, 64) 18 return &buf 19 }, 20 } 21 ) 22 23 // getGoidByStack parse the current goroutine's id from caller stack. 24 // This function could be very slow(like 3000us/op), but it's very safe. 25 func getGoidByStack() (goid int64) { 26 bp := stackBufPool.Get().(*[]byte) 27 defer stackBufPool.Put(bp) 28 29 b := *bp 30 b = b[:runtime.Stack(b, false)] 31 goid, _ = findNextGoid(b, 0) 32 return 33 } 34 35 // getAllGoidByStack find all goid through stack; WARNING: This function could be very inefficient 36 func getAllGoidByStack() (goids []int64) { 37 count := runtime.NumGoroutine() 38 size := count * stackSize // it's ok? 39 buf := make([]byte, size) 40 n := runtime.Stack(buf, true) 41 buf = buf[:n] 42 // parse all goids 43 goids = make([]int64, 0, count+4) 44 for i := 0; i < len(buf); { 45 goid, off := findNextGoid(buf, i) 46 if goid > 0 { 47 goids = append(goids, goid) 48 } 49 i = off 50 } 51 return 52 } 53 54 // Find the next goid from `buf[off:]` 55 func findNextGoid(buf []byte, off int) (goid int64, next int) { 56 i := off 57 hit := false 58 // skip to anchor 59 acr := anchor 60 for sb := len(buf) - len(acr); i < sb; { 61 if buf[i] == acr[0] && buf[i+1] == acr[1] && buf[i+2] == acr[2] && buf[i+3] == acr[3] && 62 buf[i+4] == acr[4] && buf[i+5] == acr[5] && buf[i+6] == acr[6] && 63 buf[i+7] == acr[7] && buf[i+8] == acr[8] && buf[i+9] == acr[9] { 64 hit = true 65 i += len(acr) 66 break 67 } 68 for ; i < len(buf) && buf[i] != '\n'; i++ { 69 } 70 i++ 71 } 72 // return if not hit 73 if !hit { 74 return 0, len(buf) 75 } 76 // extract goid 77 var done bool 78 for ; i < len(buf) && !done; i++ { 79 switch buf[i] { 80 case '0': 81 goid *= 10 82 case '1': 83 goid = goid*10 + 1 84 case '2': 85 goid = goid*10 + 2 86 case '3': 87 goid = goid*10 + 3 88 case '4': 89 goid = goid*10 + 4 90 case '5': 91 goid = goid*10 + 5 92 case '6': 93 goid = goid*10 + 6 94 case '7': 95 goid = goid*10 + 7 96 case '8': 97 goid = goid*10 + 8 98 case '9': 99 goid = goid*10 + 9 100 case ' ': 101 done = true 102 break 103 default: 104 goid = 0 105 log.Printf("should never be here, any bug happens\n") 106 } 107 } 108 next = i 109 return 110 }