github.com/slava-ustovytski/docker@v1.8.2-rc1/pkg/signal/trap.go (about) 1 package signal 2 3 import ( 4 "os" 5 gosignal "os/signal" 6 "runtime" 7 "sync/atomic" 8 "syscall" 9 10 "github.com/Sirupsen/logrus" 11 ) 12 13 // Trap sets up a simplified signal "trap", appropriate for common 14 // behavior expected from a vanilla unix command-line tool in general 15 // (and the Docker engine in particular). 16 // 17 // * If SIGINT or SIGTERM are received, `cleanup` is called, then the process is terminated. 18 // * If SIGINT or SIGTERM are received 3 times before cleanup is complete, then cleanup is 19 // skipped and the process is terminated immediately (allows force quit of stuck daemon) 20 // * A SIGQUIT always causes an exit without cleanup, with a goroutine dump preceding exit. 21 // 22 func Trap(cleanup func()) { 23 c := make(chan os.Signal, 1) 24 // we will handle INT, TERM, QUIT here 25 signals := []os.Signal{os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT} 26 gosignal.Notify(c, signals...) 27 go func() { 28 interruptCount := uint32(0) 29 for sig := range c { 30 go func(sig os.Signal) { 31 logrus.Infof("Processing signal '%v'", sig) 32 switch sig { 33 case os.Interrupt, syscall.SIGTERM: 34 if atomic.LoadUint32(&interruptCount) < 3 { 35 // Initiate the cleanup only once 36 if atomic.AddUint32(&interruptCount, 1) == 1 { 37 // Call the provided cleanup handler 38 cleanup() 39 os.Exit(0) 40 } else { 41 return 42 } 43 } else { 44 // 3 SIGTERM/INT signals received; force exit without cleanup 45 logrus.Infof("Forcing docker daemon shutdown without cleanup; 3 interrupts received") 46 } 47 case syscall.SIGQUIT: 48 DumpStacks() 49 logrus.Infof("Forcing docker daemon shutdown without cleanup on SIGQUIT") 50 } 51 //for the SIGINT/TERM, and SIGQUIT non-clean shutdown case, exit with 128 + signal # 52 os.Exit(128 + int(sig.(syscall.Signal))) 53 }(sig) 54 } 55 }() 56 } 57 58 func DumpStacks() { 59 buf := make([]byte, 16384) 60 buf = buf[:runtime.Stack(buf, true)] 61 // Note that if the daemon is started with a less-verbose log-level than "info" (the default), the goroutine 62 // traces won't show up in the log. 63 logrus.Infof("=== BEGIN goroutine stack dump ===\n%s\n=== END goroutine stack dump ===", buf) 64 }