tools/perf/builtin-lock.c | 20 ++++++++++++++++++-- tools/perf/builtin-sched.c | 30 ++++++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 6 deletions(-)
Some 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 (via sigprocmask) before starting the workload. If the child exits, the signal remains pending rather than being delivered and lost. 2. Replace pause() with sigsuspend(&oldmask), which atomically unblocks SIGCHLD and suspends the process. There is no window where the signal can slip through unnoticed. 3. Restore the original signal mask after sigsuspend() returns. SIGINT and SIGTERM are not blocked at any point, so Ctrl+C and graceful termination continue to work exactly as before. 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. 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 | 20 ++++++++++++++++++-- tools/perf/builtin-sched.c | 30 ++++++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 6 deletions(-) -- 2.43.0
On 01/04/2026 7:41 am, Swapnil Sapkal wrote: > Some 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 (via sigprocmask) before starting the workload. > If the child exits, the signal remains pending rather than being > delivered and lost. > > 2. Replace pause() with sigsuspend(&oldmask), which atomically > unblocks SIGCHLD and suspends the process. There is no window > where the signal can slip through unnoticed. > > 3. Restore the original signal mask after sigsuspend() returns. > > SIGINT and SIGTERM are not blocked at any point, so Ctrl+C and > graceful termination continue to work exactly as before. > > 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. > > 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 | 20 ++++++++++++++++++-- > tools/perf/builtin-sched.c | 30 ++++++++++++++++++++++++++---- > 2 files changed, 44 insertions(+), 6 deletions(-) > Reviewed-by: James Clark <james.clark@linaro.org>
© 2016 - 2026 Red Hat, Inc.