lib/atexit: factor from cmd so it can be used by backend/cache #1946

This commit is contained in:
Nick Craig-Wood 2018-01-25 10:10:21 +00:00
parent dbabb18b0c
commit fa500e6d21
3 changed files with 50 additions and 48 deletions

View File

@ -1,45 +0,0 @@
package cmd
// Atexit handling
import (
"os"
"os/signal"
"sync"
"github.com/ncw/rclone/fs"
)
var (
atExitFns []func()
atExitOnce sync.Once
atExitRegisterOnce sync.Once
)
// AtExit registers a function to be added on exit
func AtExit(fn func()) {
atExitFns = append(atExitFns, fn)
// Run AtExit handlers on SIGINT or SIGTERM so everything gets
// tidied up properly
atExitRegisterOnce.Do(func() {
go func() {
ch := make(chan os.Signal, 1)
signal.Notify(ch, os.Interrupt) // syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT
sig := <-ch
fs.Infof(nil, "Signal received: %s", sig)
runAtExitFunctions()
fs.Infof(nil, "Exiting...")
os.Exit(0)
}()
})
}
// Runs all the AtExit functions if they haven't been run already
func runAtExitFunctions() {
atExitOnce.Do(func() {
for _, fn := range atExitFns {
fn()
}
})
}

View File

@ -30,6 +30,7 @@ import (
"github.com/ncw/rclone/fs/fserrors"
"github.com/ncw/rclone/fs/fspath"
fslog "github.com/ncw/rclone/fs/log"
"github.com/ncw/rclone/lib/atexit"
)
// Globals
@ -105,7 +106,7 @@ and configuration walkthroughs.
`,
PersistentPostRun: func(cmd *cobra.Command, args []string) {
fs.Debugf("rclone", "Version %q finishing with parameters %q", fs.Version, os.Args)
runAtExitFunctions()
atexit.Run()
},
}
@ -395,14 +396,14 @@ func initConfig() {
fs.CountError(err)
log.Fatal(err)
}
AtExit(func() {
atexit.Register(func() {
pprof.StopCPUProfile()
})
}
// Setup memory profiling if desired
if *memProfile != "" {
AtExit(func() {
atexit.Register(func() {
fs.Infof(nil, "Saving Memory profile %q\n", *memProfile)
f, err := os.Create(*memProfile)
if err != nil {

46
lib/atexit/atexit.go Normal file
View File

@ -0,0 +1,46 @@
// Package atexit provides handling for functions you want called when
// the program exits unexpectedly due to a signal.
//
// You should also make sure you call Run in the normal exit path.
package atexit
import (
"os"
"os/signal"
"sync"
"github.com/ncw/rclone/fs"
)
var (
fns []func()
exitOnce sync.Once
registerOnce sync.Once
)
// Register a function to be called on exit
func Register(fn func()) {
fns = append(fns, fn)
// Run AtExit handlers on SIGINT or SIGTERM so everything gets
// tidied up properly
registerOnce.Do(func() {
go func() {
ch := make(chan os.Signal, 1)
signal.Notify(ch, os.Interrupt) // syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT
sig := <-ch
fs.Infof(nil, "Signal received: %s", sig)
Run()
fs.Infof(nil, "Exiting...")
os.Exit(0)
}()
})
}
// Run all the at exit functions if they haven't been run already
func Run() {
exitOnce.Do(func() {
for _, fn := range fns {
fn()
}
})
}