1
2
3
4
5 package main
6
7 import (
8 "flag"
9 "fmt"
10 "os"
11 "runtime"
12 "runtime/pprof"
13 )
14
15 var finalizerDeadlockMode = flag.String("finalizer-deadlock-mode", "panic", "Trigger mode of FinalizerDeadlock")
16
17 func init() {
18 register("FinalizerDeadlock", func() { FinalizerOrCleanupDeadlock(false) })
19 register("CleanupDeadlock", func() { FinalizerOrCleanupDeadlock(true) })
20 }
21
22 func FinalizerOrCleanupDeadlock(useCleanup bool) {
23 flag.Parse()
24
25 started := make(chan struct{})
26 fn := func() {
27 started <- struct{}{}
28 select {}
29 }
30 b := new([16]byte)
31 if useCleanup {
32 runtime.AddCleanup(b, func(struct{}) { fn() }, struct{}{})
33 } else {
34 runtime.SetFinalizer(b, func(*[16]byte) { fn() })
35 }
36 b = nil
37
38 runtime.GC()
39
40 <-started
41
42
43
44
45 mode := os.Getenv("GO_TEST_FINALIZER_DEADLOCK")
46 switch mode {
47 case "panic":
48 panic("panic")
49 case "stack":
50 buf := make([]byte, 4096)
51 for {
52 n := runtime.Stack(buf, true)
53 if n >= len(buf) {
54 buf = make([]byte, 2*len(buf))
55 continue
56 }
57 buf = buf[:n]
58 break
59 }
60 fmt.Printf("%s\n", string(buf))
61 case "pprof_proto":
62 if err := pprof.Lookup("goroutine").WriteTo(os.Stdout, 0); err != nil {
63 fmt.Fprintf(os.Stderr, "Error writing profile: %v\n", err)
64 os.Exit(1)
65 }
66 case "pprof_debug1":
67 if err := pprof.Lookup("goroutine").WriteTo(os.Stdout, 1); err != nil {
68 fmt.Fprintf(os.Stderr, "Error writing profile: %v\n", err)
69 os.Exit(1)
70 }
71 case "pprof_debug2":
72 if err := pprof.Lookup("goroutine").WriteTo(os.Stdout, 2); err != nil {
73 fmt.Fprintf(os.Stderr, "Error writing profile: %v\n", err)
74 os.Exit(1)
75 }
76 default:
77 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)
78 os.Exit(1)
79 }
80 }
81
View as plain text