mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
perf sched stats: Fix SIGCHLD vs pause() race in schedstat_record()
If the profiled workload exits very quickly, SIGCHLD can be delivered and consumed by the empty signal handler before the process enters pause(), causing an indefinite hang. Fix this with a simpler approach: - The signal handler now sets a 'volatile sig_atomic_t done' flag. Reset 'done' before registering signal handlers so that an early signal during setup is not discarded by a later reset. - Replace pause() with a loop that checks 'done' and uses waitpid(WNOHANG) to detect child exit without blocking. This handles both workload mode (child exits) and system-wide mode (user sends SIGINT/SIGTERM). Using WNOHANG avoids the SA_RESTART problem where a blocking waitpid() would auto-restart and ignore the done flag if the child doesn't exit on signal. Suggested-by: Namhyung Kim <namhyung@kernel.org> Assisted-by: Claude:claude-opus-4.6 Signed-off-by: Swapnil Sapkal <swapnil.sapkal@amd.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Ian Rogers <irogers@google.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Clark <james.clark@linaro.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ravi Bangoria <ravi.bangoria@amd.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
9aa1ec2e1d
commit
9416008e54
|
|
@ -36,6 +36,7 @@
|
|||
#include <linux/zalloc.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/wait.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
|
@ -3746,8 +3747,11 @@ static int process_synthesized_schedstat_event(const struct perf_tool *tool,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static volatile sig_atomic_t done;
|
||||
|
||||
static void sighandler(int sig __maybe_unused)
|
||||
{
|
||||
done = 1;
|
||||
}
|
||||
|
||||
static int enable_sched_schedstats(int *reset)
|
||||
|
|
@ -3807,6 +3811,7 @@ static int perf_sched__schedstat_record(struct perf_sched *sched,
|
|||
.mode = PERF_DATA_MODE_WRITE,
|
||||
};
|
||||
|
||||
done = 0;
|
||||
signal(SIGINT, sighandler);
|
||||
signal(SIGCHLD, sighandler);
|
||||
signal(SIGTERM, sighandler);
|
||||
|
|
@ -3891,8 +3896,11 @@ static int perf_sched__schedstat_record(struct perf_sched *sched,
|
|||
if (argc)
|
||||
evlist__start_workload(evlist);
|
||||
|
||||
/* wait for signal */
|
||||
pause();
|
||||
while (!done) {
|
||||
if (argc && waitpid(evlist->workload.pid, NULL, WNOHANG) > 0)
|
||||
break;
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
if (reset) {
|
||||
err = disable_sched_schedstat();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user