debug: properly handle interrupted profiles

By default (i.e., without profile.NoShutdownHook), profile.Start listens
for SIGINT and will stop the profile and call os.Exit(0).

restic already listens for SIGINT and runs its own cleanup handlers
before calling os.Exit(0).

As is, these handlers are racing when an interrupt occurs, and in my
experience, restic tends to win the race, resulting in an unusable
profile.

Eliminate the race and properly stop profiles on interrupt by disabling
package profile's signal handler and instead stop the profile in a
restic cleanup handler.
This commit is contained in:
Michael Pratt 2017-08-28 21:54:01 -07:00
parent 22e96a37f8
commit e4c469c149
3 changed files with 13 additions and 18 deletions

View File

@ -19,10 +19,6 @@ var (
memProfilePath string
cpuProfilePath string
insecure bool
prof interface {
Stop()
}
)
func init() {
@ -54,10 +50,21 @@ func runDebug() error {
return errors.Fatal("only one profile (memory or CPU) may be activated at the same time")
}
var prof interface {
Stop()
}
if memProfilePath != "" {
prof = profile.Start(profile.Quiet, profile.MemProfile, profile.ProfilePath(memProfilePath))
prof = profile.Start(profile.Quiet, profile.NoShutdownHook, profile.MemProfile, profile.ProfilePath(memProfilePath))
} else if cpuProfilePath != "" {
prof = profile.Start(profile.Quiet, profile.CPUProfile, profile.ProfilePath(cpuProfilePath))
prof = profile.Start(profile.Quiet, profile.NoShutdownHook, profile.CPUProfile, profile.ProfilePath(cpuProfilePath))
}
if prof != nil {
AddCleanupHandler(func() error {
prof.Stop()
return nil
})
}
if insecure {
@ -66,9 +73,3 @@ func runDebug() error {
return nil
}
func shutdownDebug() {
if prof != nil {
prof.Stop()
}
}

View File

@ -4,6 +4,3 @@ package main
// runDebug is a noop without the debug tag.
func runDebug() error { return nil }
// shutdownDebug is a noop without the debug tag.
func shutdownDebug() {}

View File

@ -52,9 +52,6 @@ directories in an encrypted repository stored on different backends.
return nil
},
PersistentPostRun: func(*cobra.Command, []string) {
shutdownDebug()
},
}
var logBuffer = bytes.NewBuffer(nil)