| | |
| | |
| | |
| |
|
| | 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 |
| | |
| | |
| | |
| |
|
| | 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) |
| | } |
| | } |
| |
|