diff --git a/cmd/cmd.go b/cmd/cmd.go index 46f0ae2d7..1f0189e2f 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -17,6 +17,7 @@ import ( "runtime/pprof" "strconv" "strings" + "sync" "time" "github.com/pkg/errors" @@ -293,7 +294,7 @@ func ShowStats() bool { // Run the function with stats and retries if required func Run(Retry bool, showStats bool, cmd *cobra.Command, f func() error) { var err error - var stopStats chan struct{} + stopStats := func() {} if !showStats && ShowStats() { showStats = true } @@ -331,9 +332,7 @@ func Run(Retry bool, showStats bool, cmd *cobra.Command, f func() error) { time.Sleep(*retriesInterval) } } - if showStats { - close(stopStats) - } + stopStats() if err != nil { log.Printf("Failed to %s: %v", cmd.Name(), err) resolveExitCode(err) @@ -384,24 +383,31 @@ func CheckArgs(MinArgs, MaxArgs int, cmd *cobra.Command, args []string) { // StartStats prints the stats every statsInterval // -// It returns a channel which should be closed to stop the stats. -func StartStats() chan struct{} { - stopStats := make(chan struct{}) - if *statsInterval > 0 { - go func() { - ticker := time.NewTicker(*statsInterval) - for { - select { - case <-ticker.C: - accounting.Stats.Log() - case <-stopStats: - ticker.Stop() - return - } - } - }() +// It returns a func which should be called to stop the stats. +func StartStats() func() { + if *statsInterval <= 0 { + return func() {} + } + stopStats := make(chan struct{}) + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + ticker := time.NewTicker(*statsInterval) + for { + select { + case <-ticker.C: + accounting.Stats.Log() + case <-stopStats: + ticker.Stop() + return + } + } + }() + return func() { + close(stopStats) + wg.Wait() } - return stopStats } // initConfig is run by cobra after initialising the flags diff --git a/cmd/mountlib/mount.go b/cmd/mountlib/mount.go index f3fe2ae4f..231923ee6 100644 --- a/cmd/mountlib/mount.go +++ b/cmd/mountlib/mount.go @@ -226,8 +226,7 @@ be copied to the vfs cache before opening with --vfs-cache-mode full. // Show stats if the user has specifically requested them if cmd.ShowStats() { - stopStats := cmd.StartStats() - defer close(stopStats) + defer cmd.StartStats()() } // Skip checkMountEmpty if --allow-non-empty flag is used or if diff --git a/cmd/progress.go b/cmd/progress.go index d2873f942..fe1a68be0 100644 --- a/cmd/progress.go +++ b/cmd/progress.go @@ -25,8 +25,8 @@ const ( // startProgress starts the progress bar printing // -// It returns a channel which should be closed to stop the stats. -func startProgress() chan struct{} { +// It returns a func which should be called to stop the stats. +func startProgress() func() { stopStats := make(chan struct{}) oldLogPrint := fs.LogPrint if !log.Redirected() { @@ -36,7 +36,10 @@ func startProgress() chan struct{} { } } + var wg sync.WaitGroup + wg.Add(1) go func() { + defer wg.Done() progressInterval := defaultProgressInterval if ShowStats() && *statsInterval > 0 { progressInterval = *statsInterval @@ -54,7 +57,10 @@ func startProgress() chan struct{} { } } }() - return stopStats + return func() { + close(stopStats) + wg.Wait() + } } // VT100 codes