cmd/dockerd: use default SIGQUIT behaviour
dockerd handles SIGQUIT by dumping all goroutine stacks to standard error and exiting. In contrast, the Go runtime's default SIGQUIT behaviour... dumps all goroutine stacks to standard error and exits. The default SIGQUIT behaviour is implemented directly in the runtime's signal handler, and so is both more robust to bugs in the Go runtime and does not perturb the state of the process to anywhere near same degree as dumping goroutine stacks from a user goroutine. The only notable difference from a user's perspective is that the process exits with status 2 instead of 128+SIGQUIT. Signed-off-by: Cory Snider <csnider@mirantis.com>
This commit is contained in:
parent
62296f9281
commit
0867d3173c
2 changed files with 4 additions and 12 deletions
|
@ -3,11 +3,9 @@ package trap // import "github.com/docker/docker/cmd/dockerd/trap"
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
gosignal "os/signal"
|
||||
"os/signal"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/docker/pkg/stack"
|
||||
)
|
||||
|
||||
// Trap sets up a simplified signal "trap", appropriate for common
|
||||
|
@ -17,7 +15,6 @@ import (
|
|||
// - 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
|
||||
|
@ -25,9 +22,8 @@ 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...)
|
||||
// we will handle INT, TERM, SIGPIPE here
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGPIPE)
|
||||
go func() {
|
||||
interruptCount := uint32(0)
|
||||
for sig := range c {
|
||||
|
@ -52,11 +48,8 @@ func Trap(cleanup func(), logger interface {
|
|||
// 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 #
|
||||
// for the SIGINT/TERM non-clean shutdown case, exit with 128 + signal #
|
||||
os.Exit(128 + int(sig.(syscall.Signal)))
|
||||
}(sig)
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@ func TestTrap(t *testing.T) {
|
|||
multiple bool
|
||||
}{
|
||||
{"TERM", syscall.SIGTERM, false},
|
||||
{"QUIT", syscall.SIGQUIT, true},
|
||||
{"INT", os.Interrupt, false},
|
||||
{"TERM", syscall.SIGTERM, true},
|
||||
{"INT", os.Interrupt, true},
|
||||
|
|
Loading…
Reference in a new issue