daemon/command: setupConfigReloadTrap: handle context cancellation

Pass the daemon lifecycle context to the config reload trap and stop the
Unix signal handler when the context is canceled. This also unregisters
the SIGHUP notification when the goroutine exits.

On Windows, signal the Win32 event when the context is canceled to wake
the blocking wait and allow the reload goroutine to exit.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn committed 2026-10-06 12:11:28 +02:00
1 parent 390fba50fe
commit 6e7e2aefa5
3 files changed
+31 -8

No files matched your search

+1 -1
View File
@@ -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")
+14 -3
View File
@@ -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()
}
}
}()
}
+16 -4
View File
@@ -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()
}
}()