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:
Cory Snider 2023-01-10 16:49:57 -05:00
parent 62296f9281
commit 0867d3173c
2 changed files with 4 additions and 12 deletions

View file

@ -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)
}

View file

@ -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},