github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/cmd/dockerd/trap/trap.go (about) 1 package trap // import "github.com/docker/docker/cmd/dockerd/trap" 2 3 import ( 4 "fmt" 5 "os" 6 gosignal "os/signal" 7 "sync/atomic" 8 "syscall" 9 10 "github.com/docker/docker/pkg/stack" 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 // - Ignore SIGPIPE events. These are generated by systemd when journald is restarted while 22 // the docker daemon is not restarted and also running under systemd. 23 // Fixes https://github.com/docker/docker/issues/19728 24 func Trap(cleanup func(), logger interface { 25 Info(args ...interface{}) 26 }) { 27 c := make(chan os.Signal, 1) 28 // we will handle INT, TERM, QUIT, SIGPIPE here 29 signals := []os.Signal{os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGPIPE} 30 gosignal.Notify(c, signals...) 31 go func() { 32 interruptCount := uint32(0) 33 for sig := range c { 34 if sig == syscall.SIGPIPE { 35 continue 36 } 37 38 go func(sig os.Signal) { 39 logger.Info(fmt.Sprintf("Processing signal '%v'", sig)) 40 switch sig { 41 case os.Interrupt, syscall.SIGTERM: 42 if atomic.LoadUint32(&interruptCount) < 3 { 43 // Initiate the cleanup only once 44 if atomic.AddUint32(&interruptCount, 1) == 1 { 45 // Call the provided cleanup handler 46 cleanup() 47 os.Exit(0) 48 } else { 49 return 50 } 51 } else { 52 // 3 SIGTERM/INT signals received; force exit without cleanup 53 logger.Info("Forcing docker daemon shutdown without cleanup; 3 interrupts received") 54 } 55 case syscall.SIGQUIT: 56 stack.Dump() 57 logger.Info("Forcing docker daemon shutdown without cleanup on SIGQUIT") 58 } 59 // for the SIGINT/TERM, and SIGQUIT non-clean shutdown case, exit with 128 + signal # 60 os.Exit(128 + int(sig.(syscall.Signal))) 61 }(sig) 62 } 63 }() 64 }