1

The following

func a() { b() }
func b() { c() }
func c() { d() }
func d() {
    pc := make([]uintptr, 10)
    n := runtime.Callers(1, pc)
    if n == 0 {
        return
    }

    frames := runtime.CallersFrames(pc[:n])

    for {
        frame, more := frames.Next()

        fmt.Println(frame.Function)

        if !more {
            break
        }
    }

}

func main() {
    a()
    // The reason for this sleep will become apparent in an incoming example
    // where we spawn a goroutine and do not explicitely wait for it to finish
    time.Sleep(time.Second)
}

outputs

main.d
main.c
main.b
main.a
main.main
runtime.main
runtime.goexit

as I expected. I am facing a situation where function c is called in a separate goroutine

func b() { go c() }

In such cas it outputs

main.d
main.c
runtime.goexit

, while I wished it to outpout the same as above.

Is there a solution to this problem? Maybe something to capture a call stack and pass it to function d? Note that performance will matter and I wish to avoid processing the stack beforehand as in my real life example, d might or might not need to trigger the call to runtime.Callers.

Remi.b
  • 17,389
  • 28
  • 87
  • 168
  • closely related: https://stackoverflow.com/questions/42692654/how-to-get-real-file-name-by-runtime-caller-called-by-anonymous-function-in-diff – blackgreen Jun 08 '22 at 12:30

1 Answers1

2

There is no solution. When you launch a function as another goroutine, it will run completely independent from the launching goroutine. The launcher may move on or completely finish / terminate. The "starting" stack is not retained for obvious reasons.

So unless you explicitly query and retain / pass the stack yourself when launching another goroutine, you'll lose it.

Note: it's possible to detect if a function is launched as a goroutine or not, and you could limit querying and retaining the stack only if so, and not in all cases. For details, see Check if function is being called as goroutine or not.

icza
  • 389,944
  • 63
  • 907
  • 827