github.com/adityamillind98/moby@v23.0.0-rc.4+incompatible/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 "os/signal" 7 "sync/atomic" 8 "syscall" 9 ) 10 11 // Trap sets up a simplified signal "trap", appropriate for common 12 // behavior expected from a vanilla unix command-line tool in general 13 // (and the Docker engine in particular). 14 // 15 // - If SIGINT or SIGTERM are received, `cleanup` is called, then the process is terminated. 16 // - If SIGINT or SIGTERM are received 3 times before cleanup is complete, then cleanup is 17 // skipped and the process is terminated immediately (allows force quit of stuck daemon) 18 // - Ignore SIGPIPE events. These are generated by systemd when journald is restarted while 19 // the docker daemon is not restarted and also running under systemd. 20 // Fixes https://github.com/docker/docker/issues/19728 21 func Trap(cleanup func(), logger interface { 22 Info(args ...interface{}) 23 }) { 24 c := make(chan os.Signal, 1) 25 // we will handle INT, TERM, SIGPIPE here 26 signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGPIPE) 27 go func() { 28 interruptCount := uint32(0) 29 for sig := range c { 30 if sig == syscall.SIGPIPE { 31 continue 32 } 33 34 go func(sig os.Signal) { 35 logger.Info(fmt.Sprintf("Processing signal '%v'", sig)) 36 switch sig { 37 case os.Interrupt, syscall.SIGTERM: 38 if atomic.LoadUint32(&interruptCount) < 3 { 39 // Initiate the cleanup only once 40 if atomic.AddUint32(&interruptCount, 1) == 1 { 41 // Call the provided cleanup handler 42 cleanup() 43 os.Exit(0) 44 } else { 45 return 46 } 47 } else { 48 // 3 SIGTERM/INT signals received; force exit without cleanup 49 logger.Info("Forcing docker daemon shutdown without cleanup; 3 interrupts received") 50 } 51 } 52 // for the SIGINT/TERM non-clean shutdown case, exit with 128 + signal # 53 os.Exit(128 + int(sig.(syscall.Signal))) 54 }(sig) 55 } 56 }() 57 }