| package trap // import "github.com/docker/docker/cmd/dockerd/trap" | |
| import ( | |
| "context" | |
| "os" | |
| "os/signal" | |
| "syscall" | |
| "github.com/containerd/log" | |
| ) | |
| const ( | |
| // Immediately terminate the process when this many SIGINT or SIGTERM | |
| // signals are received. | |
| forceQuitCount = 3 | |
| ) | |
| // Trap sets up a simplified signal "trap", appropriate for common | |
| // behavior expected from a vanilla unix command-line tool in general | |
| // (and the Docker engine in particular). | |
| // | |
| // The first time a SIGINT or SIGTERM signal is received, `cleanup` is called in | |
| // a new goroutine. | |
| // | |
| // If SIGINT or SIGTERM are received 3 times, the process is terminated | |
| // immediately with an exit code of 128 + the signal number. | |
| func Trap(cleanup func()) { | |
| c := make(chan os.Signal, forceQuitCount) | |
| signal.Notify(c, os.Interrupt, syscall.SIGTERM) | |
| go func() { | |
| var interruptCount int | |
| for sig := range c { | |
| log.G(context.TODO()).Infof("Processing signal '%v'", sig) | |
| if interruptCount < forceQuitCount { | |
| interruptCount++ | |
| // Initiate the cleanup only once | |
| if interruptCount == 1 { | |
| go cleanup() | |
| } | |
| continue | |
| } | |
| log.G(context.TODO()).Info("Forcing docker daemon shutdown without cleanup; 3 interrupts received") | |
| os.Exit(128 + int(sig.(syscall.Signal))) | |
| } | |
| }() | |
| } |