github.com/titanous/docker@v1.4.1/pkg/signal/trap.go (about) 1 package signal 2 3 import ( 4 "os" 5 gosignal "os/signal" 6 "sync/atomic" 7 "syscall" 8 9 log "github.com/Sirupsen/logrus" 10 ) 11 12 // Trap sets up a simplified signal "trap", appropriate for common 13 // behavior expected from a vanilla unix command-line tool in general 14 // (and the Docker engine in particular). 15 // 16 // * If SIGINT or SIGTERM are received, `cleanup` is called, then the process is terminated. 17 // * If SIGINT or SIGTERM are repeated 3 times before cleanup is complete, then cleanup is 18 // skipped and the process terminated directly. 19 // * If "DEBUG" is set in the environment, SIGQUIT causes an exit without cleanup. 20 // 21 func Trap(cleanup func()) { 22 c := make(chan os.Signal, 1) 23 signals := []os.Signal{os.Interrupt, syscall.SIGTERM} 24 if os.Getenv("DEBUG") == "" { 25 signals = append(signals, syscall.SIGQUIT) 26 } 27 gosignal.Notify(c, signals...) 28 go func() { 29 interruptCount := uint32(0) 30 for sig := range c { 31 go func(sig os.Signal) { 32 log.Infof("Received signal '%v', starting shutdown of docker...", sig) 33 switch sig { 34 case os.Interrupt, syscall.SIGTERM: 35 // If the user really wants to interrupt, let him do so. 36 if atomic.LoadUint32(&interruptCount) < 3 { 37 // Initiate the cleanup only once 38 if atomic.AddUint32(&interruptCount, 1) == 1 { 39 // Call cleanup handler 40 cleanup() 41 os.Exit(0) 42 } else { 43 return 44 } 45 } else { 46 log.Infof("Force shutdown of docker, interrupting cleanup") 47 } 48 case syscall.SIGQUIT: 49 } 50 os.Exit(128 + int(sig.(syscall.Signal))) 51 }(sig) 52 } 53 }() 54 }