From 9d5cd39e83d837a429c41329175acd491c7126f0 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Fri, 12 Apr 2024 19:28:16 +0300 Subject: [PATCH] Pull request 107: svc-windows Squashed commit of the following: commit 6c9085076557d4b429c43bf891381808408174ba Author: Ainar Garipov Date: Fri Apr 12 19:01:08 2024 +0300 osutil, service: windows support --- osutil/signal.go | 10 ++++++++++ osutil/signal_unix.go | 27 +++++++++++++++++++++++++++ osutil/signal_windows.go | 26 ++++++++++++++++++++++++++ service/service_test.go | 2 -- service/signal.go | 15 ++------------- service/signal_test.go | 2 -- testutil/context.go | 18 ++++++++++++++++++ 7 files changed, 83 insertions(+), 17 deletions(-) create mode 100644 osutil/signal_unix.go create mode 100644 osutil/signal_windows.go create mode 100644 testutil/context.go diff --git a/osutil/signal.go b/osutil/signal.go index adf08ec..e9e03ab 100644 --- a/osutil/signal.go +++ b/osutil/signal.go @@ -52,3 +52,13 @@ func (n DefaultSignalNotifier) Notify(c chan<- os.Signal, sig ...os.Signal) { func (n DefaultSignalNotifier) Stop(c chan<- os.Signal) { signal.Stop(c) } + +// IsShutdownSignal returns true if sig is a shutdown signal. +func IsShutdownSignal(sig os.Signal) (ok bool) { + return isShutdownSignal(sig) +} + +// NotifyShutdownSignal notifies c on receiving shutdown signals using n. +func NotifyShutdownSignal(n SignalNotifier, c chan<- os.Signal) { + notifyShutdownSignal(n, c) +} diff --git a/osutil/signal_unix.go b/osutil/signal_unix.go new file mode 100644 index 0000000..ebc604b --- /dev/null +++ b/osutil/signal_unix.go @@ -0,0 +1,27 @@ +//go:build unix + +package osutil + +import ( + "os" + + "golang.org/x/sys/unix" +) + +// isShutdownSignal returns true if sig is a Unix shutdown signal. +func isShutdownSignal(sig os.Signal) (ok bool) { + switch sig { + case + unix.SIGINT, + unix.SIGQUIT, + unix.SIGTERM: + return true + default: + return false + } +} + +// notifyShutdownSignal notifies c on receiving Unix shutdown signals using n. +func notifyShutdownSignal(n SignalNotifier, c chan<- os.Signal) { + n.Notify(c, unix.SIGINT, unix.SIGQUIT, unix.SIGTERM) +} diff --git a/osutil/signal_windows.go b/osutil/signal_windows.go new file mode 100644 index 0000000..300239f --- /dev/null +++ b/osutil/signal_windows.go @@ -0,0 +1,26 @@ +//go:build windows + +package osutil + +import ( + "os" + "syscall" +) + +// isShutdownSignal returns true if sig is a Windows shutdown signal. +func isShutdownSignal(sig os.Signal) (ok bool) { + switch sig { + case os.Interrupt, syscall.SIGTERM: + return true + default: + return false + } +} + +// notifyShutdownSignal notifies c on receiving Windows shutdown signals using +// n. +func notifyShutdownSignal(n SignalNotifier, c chan<- os.Signal) { + // syscall.SIGTERM is processed automatically. See go doc os/signal, + // section Windows. + n.Notify(c, os.Interrupt) +} diff --git a/service/service_test.go b/service/service_test.go index aac3c71..cbb66dd 100644 --- a/service/service_test.go +++ b/service/service_test.go @@ -1,5 +1,3 @@ -//go:build unix - package service_test import "time" diff --git a/service/signal.go b/service/signal.go index c6605e2..2f939fa 100644 --- a/service/signal.go +++ b/service/signal.go @@ -1,5 +1,3 @@ -//go:build unix - package service import ( @@ -11,12 +9,9 @@ import ( "github.com/AdguardTeam/golibs/logutil/slogutil" "github.com/AdguardTeam/golibs/osutil" - "golang.org/x/sys/unix" ) // SignalHandler processes incoming signals and shuts services down. -// -// TODO(a.garipov): Expand to Windows. type SignalHandler struct { logger *slog.Logger signal chan os.Signal @@ -73,9 +68,8 @@ func NewSignalHandler(c *SignalHandlerConfig) (h *SignalHandler) { shutdownTimeout: cmp.Or(c.ShutdownTimeout, defaultSignalHandlerConf.ShutdownTimeout), } - // TODO(a.garipov): Expand these to Windows. notifier := cmp.Or(c.SignalNotifier, defaultSignalHandlerConf.SignalNotifier) - notifier.Notify(h.signal, unix.SIGINT, unix.SIGQUIT, unix.SIGTERM) + osutil.NotifyShutdownSignal(notifier, h.signal) return h } @@ -100,12 +94,7 @@ func (h *SignalHandler) Handle(ctx context.Context) (status osutil.ExitCode) { for sig := range h.signal { h.logger.InfoContext(ctx, "received", "signal", sig) - switch sig { - case - unix.SIGINT, - unix.SIGQUIT, - unix.SIGTERM: - + if osutil.IsShutdownSignal(sig) { var cancel context.CancelFunc ctx, cancel = context.WithTimeout(ctx, h.shutdownTimeout) defer cancel() diff --git a/service/signal_test.go b/service/signal_test.go index d876544..b71a793 100644 --- a/service/signal_test.go +++ b/service/signal_test.go @@ -1,5 +1,3 @@ -//go:build unix - package service_test import ( diff --git a/testutil/context.go b/testutil/context.go new file mode 100644 index 0000000..aa9c9a8 --- /dev/null +++ b/testutil/context.go @@ -0,0 +1,18 @@ +package testutil + +import ( + "context" + "testing" + "time" +) + +// ContextWithTimeout is a helper that creates a new context with timeout and +// registers ctx's cleanup with tb.Cleanup. +func ContextWithTimeout(tb testing.TB, timeout time.Duration) (ctx context.Context) { + tb.Helper() + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + tb.Cleanup(cancel) + + return ctx +}