github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/runtime/testdata/testprog/traceback_ancestors.go (about) 1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bytes" 9 "fmt" 10 "runtime" 11 "strings" 12 ) 13 14 func init() { 15 register("TracebackAncestors", TracebackAncestors) 16 } 17 18 const numGoroutines = 3 19 const numFrames = 2 20 21 func TracebackAncestors() { 22 w := make(chan struct{}) 23 recurseThenCallGo(w, numGoroutines, numFrames, true) 24 <-w 25 printStack() 26 close(w) 27 } 28 29 var ignoreGoroutines = make(map[string]bool) 30 31 func printStack() { 32 buf := make([]byte, 1024) 33 for { 34 n := runtime.Stack(buf, true) 35 if n < len(buf) { 36 tb := string(buf[:n]) 37 38 // Delete any ignored goroutines, if present. 39 pos := 0 40 for pos < len(tb) { 41 next := pos + strings.Index(tb[pos:], "\n\n") 42 if next < pos { 43 next = len(tb) 44 } else { 45 next += len("\n\n") 46 } 47 48 if strings.HasPrefix(tb[pos:], "goroutine ") { 49 id := tb[pos+len("goroutine "):] 50 id = id[:strings.IndexByte(id, ' ')] 51 if ignoreGoroutines[id] { 52 tb = tb[:pos] + tb[next:] 53 next = pos 54 } 55 } 56 pos = next 57 } 58 59 fmt.Print(tb) 60 return 61 } 62 buf = make([]byte, 2*len(buf)) 63 } 64 } 65 66 func recurseThenCallGo(w chan struct{}, frames int, goroutines int, main bool) { 67 if frames == 0 { 68 // Signal to TracebackAncestors that we are done recursing and starting goroutines. 69 w <- struct{}{} 70 <-w 71 return 72 } 73 if goroutines == 0 { 74 // Record which goroutine this is so we can ignore it 75 // in the traceback if it hasn't finished exiting by 76 // the time we printStack. 77 if !main { 78 ignoreGoroutines[goroutineID()] = true 79 } 80 81 // Start the next goroutine now that there are no more recursions left 82 // for this current goroutine. 83 go recurseThenCallGo(w, frames-1, numFrames, false) 84 return 85 } 86 recurseThenCallGo(w, frames, goroutines-1, main) 87 } 88 89 func goroutineID() string { 90 buf := make([]byte, 128) 91 runtime.Stack(buf, false) 92 const prefix = "goroutine " 93 if !bytes.HasPrefix(buf, []byte(prefix)) { 94 panic(fmt.Sprintf("expected %q at beginning of traceback:\n%s", prefix, buf)) 95 } 96 buf = buf[len(prefix):] 97 n := bytes.IndexByte(buf, ' ') 98 return string(buf[:n]) 99 }