1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 |
- package trap // import "github.com/docker/docker/cmd/dockerd/trap"
- import (
- "fmt"
- "os"
- gosignal "os/signal"
- "sync/atomic"
- "syscall"
- "github.com/docker/docker/pkg/stack"
- )
- // 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).
- //
- // * If SIGINT or SIGTERM are received, `cleanup` is called, then the process is terminated.
- // * If SIGINT or SIGTERM are received 3 times before cleanup is complete, then cleanup is
- // skipped and the process is terminated immediately (allows force quit of stuck daemon)
- // * A SIGQUIT always causes an exit without cleanup, with a goroutine dump preceding exit.
- // * Ignore SIGPIPE events. These are generated by systemd when journald is restarted while
- // the docker daemon is not restarted and also running under systemd.
- // Fixes https://github.com/docker/docker/issues/19728
- //
- func Trap(cleanup func(), logger interface {
- Info(args ...interface{})
- }) {
- c := make(chan os.Signal, 1)
- // we will handle INT, TERM, QUIT, SIGPIPE here
- signals := []os.Signal{os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGPIPE}
- gosignal.Notify(c, signals...)
- go func() {
- interruptCount := uint32(0)
- for sig := range c {
- if sig == syscall.SIGPIPE {
- continue
- }
- go func(sig os.Signal) {
- logger.Info(fmt.Sprintf("Processing signal '%v'", sig))
- switch sig {
- case os.Interrupt, syscall.SIGTERM:
- if atomic.LoadUint32(&interruptCount) < 3 {
- // Initiate the cleanup only once
- if atomic.AddUint32(&interruptCount, 1) == 1 {
- // Call the provided cleanup handler
- cleanup()
- os.Exit(0)
- } else {
- return
- }
- } else {
- // 3 SIGTERM/INT signals received; force exit without cleanup
- logger.Info("Forcing docker daemon shutdown without cleanup; 3 interrupts received")
- }
- case syscall.SIGQUIT:
- stack.Dump()
- logger.Info("Forcing docker daemon shutdown without cleanup on SIGQUIT")
- }
- // for the SIGINT/TERM, and SIGQUIT non-clean shutdown case, exit with 128 + signal #
- os.Exit(128 + int(sig.(syscall.Signal)))
- }(sig)
- }
- }()
- }
|