public inbox for linux-perf-users@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/3] perf: Fix SIGCHLD vs pause() race with short-lived workloads
@ 2026-04-09 16:22 Swapnil Sapkal
  2026-04-09 16:22 ` [PATCH v2 1/3] perf sched stats: Fix SIGCHLD race in schedstat_record() Swapnil Sapkal
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Swapnil Sapkal @ 2026-04-09 16:22 UTC (permalink / raw)
  To: peterz, mingo, acme, namhyung, irogers, james.clark
  Cc: mark.rutland, alexander.shishkin, jolsa, adrian.hunter,
	ravi.bangoria, linux-perf-users, linux-kernel, Swapnil Sapkal

Several perf subcommands (sched stats, lock contention) use the pattern
of forking a workload child, calling evlist__start_workload() to uncork
it, and then calling pause() to wait for a signal (typically SIGCHLD
when the child exits, or SIGINT/SIGTERM from the user).

This pattern has a race condition: if the workload is very short-lived,
the child can exit and deliver SIGCHLD in the window between
evlist__start_workload() and pause(). Since pause() only returns when a
signal is received *while the process is suspended*, and SIGCHLD has
already been delivered and handled by the empty sighandler(), pause()
blocks indefinitely.

The fix uses the standard POSIX pattern for this class of bug:

1. Block SIGCHLD, SIGINT, and SIGTERM (via sigprocmask) after
   evlist__prepare_workload() returns but before
   evlist__start_workload(). Blocking after the fork ensures the
   child workload does not inherit a modified signal mask.

2. Replace pause() with sigsuspend(&oldmask), which atomically
   restores the original mask and suspends the process. There is no
   window where any signal can slip through unnoticed.

3. Restore the original signal mask after sigsuspend() returns.

All three signals are blocked (not just SIGCHLD) so that an early
Ctrl+C during the remaining setup before sigsuspend() cannot be
consumed and lost, which would cause a hang in system-wide mode where
no SIGCHLD would follow.

Three call sites are affected across two files:
  - perf_sched__schedstat_record() in builtin-sched.c
  - perf_sched__schedstat_live()   in builtin-sched.c
  - __cmd_contention()             in builtin-lock.c

The two pause() sites in builtin-kwork.c are NOT affected because they
do not register SIGCHLD or fork workload children; they only wait for
user-initiated SIGINT/SIGTERM.

Changes since v1:
  - Moved sigprocmask() to after evlist__prepare_workload() so the
    forked child does not inherit a blocked SIGCHLD mask, which would
    break workloads relying on SIGCHLD (e.g., Node.js, Python asyncio).
    (Sashiko review)
  - Block SIGINT and SIGTERM in addition to SIGCHLD to prevent an
    early Ctrl+C during setup from being consumed before sigsuspend().
  - Error paths before sigprocmask no longer need mask restoration
    since the mask is not yet modified at that point.
    (Sashiko review)

Swapnil Sapkal (3):
  perf sched stats: Fix SIGCHLD race in schedstat_record()
  perf sched stats: Fix SIGCHLD race in schedstat_live()
  perf lock contention: Fix SIGCHLD race in __cmd_contention()

 tools/perf/builtin-lock.c  | 18 ++++++++++++++++--
 tools/perf/builtin-sched.c | 30 ++++++++++++++++++++++++++----
 2 files changed, 42 insertions(+), 6 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-04-09 17:37 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-09 16:22 [PATCH v2 0/3] perf: Fix SIGCHLD vs pause() race with short-lived workloads Swapnil Sapkal
2026-04-09 16:22 ` [PATCH v2 1/3] perf sched stats: Fix SIGCHLD race in schedstat_record() Swapnil Sapkal
2026-04-09 16:51   ` sashiko-bot
2026-04-09 16:22 ` [PATCH v2 2/3] perf sched stats: Fix SIGCHLD race in schedstat_live() Swapnil Sapkal
2026-04-09 17:18   ` sashiko-bot
2026-04-09 16:22 ` [PATCH v2 3/3] perf lock contention: Fix SIGCHLD race in __cmd_contention() Swapnil Sapkal
2026-04-09 17:37   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox