diff --git a/daemon/command/daemon.go b/daemon/command/daemon.go index 2b63ea32d4..85c7709ad1 100644 --- a/daemon/command/daemon.go +++ b/daemon/command/daemon.go @@ -363,7 +363,7 @@ func (cli *daemonCLI) start(ctx context.Context) (retErr error) { go d.ProcessClusterNotifications(ctx, c.GetWatchStream()) - cli.setupConfigReloadTrap() + cli.setupConfigReloadTrap(ctx) log.G(ctx).Info("Daemon has completed initialization") diff --git a/daemon/command/daemon_unix.go b/daemon/command/daemon_unix.go index e2345074ef..9d369162df 100644 --- a/daemon/command/daemon_unix.go +++ b/daemon/command/daemon_unix.go @@ -58,12 +58,23 @@ func setDefaultUmask() error { } // setupConfigReloadTrap configures the SIGHUP signal to reload the configuration. -func (cli *daemonCLI) setupConfigReloadTrap() { +func (cli *daemonCLI) setupConfigReloadTrap(ctx context.Context) { c := make(chan os.Signal, 1) signal.Notify(c, unix.SIGHUP) + go func() { - for range c { - cli.reloadConfig() + defer signal.Stop(c) + + for { + select { + case <-ctx.Done(): + return + case <-c: + if ctx.Err() != nil { + return + } + cli.reloadConfig() + } } }() } diff --git a/daemon/command/daemon_windows.go b/daemon/command/daemon_windows.go index e5bc8e6850..3a4dd9d95f 100644 --- a/daemon/command/daemon_windows.go +++ b/daemon/command/daemon_windows.go @@ -80,9 +80,7 @@ func notifyShutdown(ctx context.Context, err error) { } // setupConfigReloadTrap configures a Win32 event to reload the configuration. -func (cli *daemonCLI) setupConfigReloadTrap() { - ctx := context.TODO() - +func (cli *daemonCLI) setupConfigReloadTrap(ctx context.Context) { go func() { event := `Global\docker-daemon-config-` + strconv.Itoa(os.Getpid()) ev, _ := windows.UTF16PtrFromString(event) @@ -91,11 +89,25 @@ func (cli *daemonCLI) setupConfigReloadTrap() { log.G(ctx).WithError(err).Errorf("Failed to create config reload event %s", event) return } - defer func() { _ = windows.CloseHandle(h) }() + stopDone := make(chan struct{}) + stop := context.AfterFunc(ctx, func() { + // Wake the blocking wait so the goroutine can exit on shutdown. + _ = windows.SetEvent(h) + close(stopDone) + }) + defer func() { + if !stop() { + <-stopDone + } + _ = windows.CloseHandle(h) + }() log.G(ctx).Debugf("Config reload - waiting signal at %s", event) for { windows.WaitForSingleObject(h, windows.INFINITE) + if ctx.Err() != nil { + return + } cli.reloadConfig() } }()