[PATCH 2/3] perf sched stats: Fix SIGCHLD race in schedstat_live()

Swapnil Sapkal posted 3 patches 15 hours ago
[PATCH 2/3] perf sched stats: Fix SIGCHLD race in schedstat_live()
Posted by Swapnil Sapkal 15 hours ago
The signal race that exists in perf_sched__schedstat_record() also
affects perf_sched__schedstat_live(). A very short-lived workload can
exit and deliver SIGCHLD before pause() is entered, causing an
indefinite hang.

Apply the same fix: block SIGCHLD before starting the workload and
replace pause() with sigsuspend() to atomically unblock and wait.

Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Swapnil Sapkal <swapnil.sapkal@amd.com>
---
 tools/perf/builtin-sched.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index eb3702d98fd1..1d8f4ceda1eb 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -4655,6 +4655,7 @@ static int perf_sched__schedstat_live(struct perf_sched *sched,
 				      int argc, const char **argv)
 {
 	struct cpu_domain_map **cd_map = NULL;
+	sigset_t sigchld_mask, oldmask;
 	struct target target = {};
 	u32 __maybe_unused md;
 	struct evlist *evlist;
@@ -4666,6 +4667,10 @@ static int perf_sched__schedstat_live(struct perf_sched *sched,
 	signal(SIGCHLD, sighandler);
 	signal(SIGTERM, sighandler);
 
+	sigemptyset(&sigchld_mask);
+	sigaddset(&sigchld_mask, SIGCHLD);
+	sigprocmask(SIG_BLOCK, &sigchld_mask, &oldmask);
+
 	evlist = evlist__new();
 	if (!evlist)
 		return -ENOMEM;
@@ -4707,8 +4712,8 @@ static int perf_sched__schedstat_live(struct perf_sched *sched,
 	if (argc)
 		evlist__start_workload(evlist);
 
-	/* wait for signal */
-	pause();
+	sigsuspend(&oldmask);
+	sigprocmask(SIG_SETMASK, &oldmask, NULL);
 
 	if (reset) {
 		err = disable_sched_schedstat();
-- 
2.43.0