From 9cd364adb068699e1e1afc6933071d8bbc6c949e Mon Sep 17 00:00:00 2001 From: Jason Harper Date: Tue, 19 Nov 2024 16:49:35 -0800 Subject: [PATCH] send SIGINT and SIGTERM to children when received (#97) --- cmd/metrics/metrics.go | 2 ++ internal/util/util.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/cmd/metrics/metrics.go b/cmd/metrics/metrics.go index e55ec14..ad4e7dc 100644 --- a/cmd/metrics/metrics.go +++ b/cmd/metrics/metrics.go @@ -504,6 +504,8 @@ func runCmd(cmd *cobra.Command, args []string) error { sig := <-sigChannel setSignalReceived() slog.Info("received signal", slog.String("signal", sig.String())) + // propogate signal to children + util.SignalChildren(sig) }() // round up to next perfPrintInterval second (the collection interval used by perf stat) if flagDuration != 0 { diff --git a/internal/util/util.go b/internal/util/util.go index 2f35ad2..90e3edf 100644 --- a/internal/util/util.go +++ b/internal/util/util.go @@ -14,8 +14,10 @@ import ( "fmt" "io" "io/fs" + "log/slog" "math" "os" + "os/exec" "os/user" "path/filepath" "regexp" @@ -403,3 +405,35 @@ func GetAppDir() string { exePath, _ := os.Executable() return filepath.Dir(exePath) } + +// SignalChildren sends a signal to all children of this process +func SignalChildren(sig os.Signal) { + // get list of child processes + cmd := exec.Command("pgrep", "-P", strconv.Itoa(os.Getpid())) + out, err := cmd.Output() + if err != nil { + slog.Error("failed to get child processes", slog.String("error", err.Error())) + return + } + // send signal to each child + for _, pid := range strings.Split(string(out), "\n") { + if pid == "" { + continue + } + pidInt, err := strconv.Atoi(pid) + if err != nil { + slog.Error("failed to convert pid to int", slog.String("pid", pid), slog.String("error", err.Error())) + continue + } + proc, err := os.FindProcess(pidInt) + if err != nil { + slog.Error("failed to find process", slog.Int("pid", pidInt), slog.String("error", err.Error())) + continue + } + slog.Info("sending signal to child process", slog.Int("pid", pidInt), slog.String("signal", sig.String())) + err = proc.Signal(sig) + if err != nil { + slog.Error("failed to send signal to process", slog.Int("pid", pidInt), slog.String("error", err.Error())) + } + } +}