diff options
| author | Michael Pratt <mpratt@google.com> | 2025-03-24 03:08:33 -0400 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2025-03-24 17:15:19 -0700 |
| commit | 9c88db5f1eba68999184bb043a0b339349b81db4 (patch) | |
| tree | 7a8a73c1624269ecf61cef4285badd602e20578a /src/runtime/testdata | |
| parent | aaf9b46800fe12c11c17bffebc82436204a1e85b (diff) | |
| download | go-9c88db5f1eba68999184bb043a0b339349b81db4.tar.xz | |
runtime: always show runfinq in traceback
Today, runtime.runfinq is hidden whenever runtime frames are hidden.
However this frame serves as a hint that this goroutine is running
finalizers, which is otherwise unclear, but can be useful when debugging
issues with finalizers.
Fixes #73011.
Change-Id: I6a6a636cb63951fbe1fefc3554fe9cea5d0a0fb6
Reviewed-on: https://go-review.googlesource.com/c/go/+/660295
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Michael Pratt <mpratt@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Diffstat (limited to 'src/runtime/testdata')
| -rw-r--r-- | src/runtime/testdata/testprog/finalizer_deadlock.go | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/src/runtime/testdata/testprog/finalizer_deadlock.go b/src/runtime/testdata/testprog/finalizer_deadlock.go new file mode 100644 index 0000000000..a55145fa15 --- /dev/null +++ b/src/runtime/testdata/testprog/finalizer_deadlock.go @@ -0,0 +1,74 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "flag" + "fmt" + "os" + "runtime" + "runtime/pprof" +) + +var finalizerDeadlockMode = flag.String("finalizer-deadlock-mode", "panic", "Trigger mode of FinalizerDeadlock") + +func init() { + register("FinalizerDeadlock", FinalizerDeadlock) +} + +func FinalizerDeadlock() { + flag.Parse() + + started := make(chan struct{}) + b := new([16]byte) + runtime.SetFinalizer(b, func(*[16]byte) { + started <- struct{}{} + select {} + }) + b = nil + + runtime.GC() + + <-started + // We know the finalizer has started running. The goroutine might still + // be running or it may now be blocked. Either is fine, the goroutine + // should appear in stacks either way. + + mode := os.Getenv("GO_TEST_FINALIZER_DEADLOCK") + switch mode { + case "panic": + panic("panic") + case "stack": + buf := make([]byte, 4096) + for { + n := runtime.Stack(buf, true) + if n >= len(buf) { + buf = make([]byte, 2*len(buf)) + continue + } + buf = buf[:n] + break + } + fmt.Printf("%s\n", string(buf)) + case "pprof_proto": + if err := pprof.Lookup("goroutine").WriteTo(os.Stdout, 0); err != nil { + fmt.Fprintf(os.Stderr, "Error writing profile: %v\n", err) + os.Exit(1) + } + case "pprof_debug1": + if err := pprof.Lookup("goroutine").WriteTo(os.Stdout, 1); err != nil { + fmt.Fprintf(os.Stderr, "Error writing profile: %v\n", err) + os.Exit(1) + } + case "pprof_debug2": + if err := pprof.Lookup("goroutine").WriteTo(os.Stdout, 2); err != nil { + fmt.Fprintf(os.Stderr, "Error writing profile: %v\n", err) + os.Exit(1) + } + default: + fmt.Fprintf(os.Stderr, "Unknown mode %q. GO_TEST_FINALIZER_DEADLOCK must be one of panic, stack, pprof_proto, pprof_debug1, pprof_debug2\n", mode) + os.Exit(1) + } +} |
