File size: 2,077 Bytes
e36aeda | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | // 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", func() { FinalizerOrCleanupDeadlock(false) })
register("CleanupDeadlock", func() { FinalizerOrCleanupDeadlock(true) })
}
func FinalizerOrCleanupDeadlock(useCleanup bool) {
flag.Parse()
started := make(chan struct{})
fn := func() {
started <- struct{}{}
select {}
}
b := new([16]byte)
if useCleanup {
runtime.AddCleanup(b, func(struct{}) { fn() }, struct{}{})
} else {
runtime.SetFinalizer(b, func(*[16]byte) { fn() })
}
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)
}
}
|