github.com/Rookout/GoSDK@v0.1.48/pkg/services/callstack/callstack.go (about) 1 package callstack 2 3 import ( 4 "github.com/Rookout/GoSDK/pkg/services/suspender" 5 "math" 6 "runtime" 7 ) 8 9 10 const ReallocateSizeAuto int = 0 11 12 type IStackTraceBuffer interface { 13 Reallocate(n int) 14 FillStackTraces() (n int, ok bool) 15 Size() int 16 GetPC(goroutineIdx, depthIdx int) uintptr 17 GetDepth(goroutineIdx int) (depth int, allFrames bool) 18 GetMaxPossibleDepth() int 19 } 20 21 type StackTraceBuffer struct { 22 buf []runtime.StackRecord 23 filled int 24 } 25 26 func NewStackTraceBuffer() IStackTraceBuffer { 27 stb := &StackTraceBuffer{} 28 stb.Reallocate(ReallocateSizeAuto) 29 return stb 30 } 31 32 func (s *StackTraceBuffer) Reallocate(n int) { 33 if suspender.GetSuspender().Stopped() { 34 panic("Can't reallocate when the world is stopped! You must call ResumeAll() first!") 35 } 36 if n == ReallocateSizeAuto || n < 0 { 37 n = runtime.NumGoroutine() 38 } 39 if n < 1 { 40 n = 1 41 } 42 extraFactor := 1.1 43 n = int(math.Ceil(float64(n) * extraFactor)) 44 s.buf = make([]runtime.StackRecord, n) 45 s.filled = 0 46 } 47 48 func (s *StackTraceBuffer) capacity() int { 49 return len(s.buf) 50 } 51 52 func (s *StackTraceBuffer) Size() int { 53 return s.filled 54 } 55 56 func (s *StackTraceBuffer) GetPC(goroutineIdx, depthIdx int) uintptr { 57 if goroutineIdx >= s.Size() || depthIdx >= len(s.buf[goroutineIdx].Stack0) { 58 return 0 59 } 60 return s.buf[goroutineIdx].Stack0[depthIdx] 61 } 62 63 func (s *StackTraceBuffer) GetDepth(goroutineIdx int) (depth int, allFrames bool) { 64 if goroutineIdx >= s.Size() { 65 return 0, false 66 } 67 buf := &s.buf[goroutineIdx] 68 i := 0 69 for ; i < len(buf.Stack0); i++ { 70 if buf.Stack0[i] == 0 { 71 break 72 } 73 } 74 return i, i < len(buf.Stack0) 75 } 76 77 func (s *StackTraceBuffer) GetMaxPossibleDepth() int { 78 if s.capacity() == 0 { 79 return 0 80 } 81 return len(s.buf[0].Stack0) 82 }