[PATCH v7] perf tpebs: Fix concurrent stop races and PID reuse hazards in tpebs_stop
From: Ian Rogers
Date: Tue Jun 02 2026 - 03:38:36 EST
Parallel verbose test execution can trigger a race condition in tpebs_stop
if called concurrently or when PID reuse occurs, causing finish_command()
to block or reap the wrong process.
Introduce a `tpebs_stopping` flag inside intel-tpebs.c to prevent
redundant stop execution paths, and safely restore the `cmd.pid`
temporarily only during `finish_command()` to ensure it is properly reaped,
while preventing other threads from referencing it.
Signed-off-by: Ian Rogers <irogers@xxxxxxxxxx>
---
tools/perf/util/intel-tpebs.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
index ed8cfe2ba2fa..ddb0579a451e 100644
--- a/tools/perf/util/intel-tpebs.c
+++ b/tools/perf/util/intel-tpebs.c
@@ -37,6 +37,7 @@ static pthread_t tpebs_reader_thread;
static struct child_process tpebs_cmd;
static int control_fd[2], ack_fd[2];
static struct mutex tpebs_mtx;
+static bool tpebs_stopping;
struct tpebs_retire_lat {
struct list_head nd;
@@ -320,8 +321,14 @@ static int tpebs_stop(void) EXCLUSIVE_LOCKS_REQUIRED(tpebs_mtx_get())
{
int ret = 0;
+ if (tpebs_stopping)
+ return 0;
+
/* Like tpebs_start, we should only run tpebs_end once. */
if (tpebs_cmd.pid != 0) {
+ pid_t actual_pid = tpebs_cmd.pid;
+
+ tpebs_stopping = true;
tpebs_send_record_cmd(EVLIST_CTL_CMD_STOP_TAG);
tpebs_cmd.pid = 0;
mutex_unlock(tpebs_mtx_get());
@@ -332,8 +339,10 @@ static int tpebs_stop(void) EXCLUSIVE_LOCKS_REQUIRED(tpebs_mtx_get())
close(ack_fd[0]);
close(ack_fd[1]);
close(tpebs_cmd.out);
+ tpebs_cmd.pid = actual_pid;
ret = finish_command(&tpebs_cmd);
tpebs_cmd.pid = 0;
+ tpebs_stopping = false;
if (ret == -ERR_RUN_COMMAND_WAITPID_SIGNAL)
ret = 0;
}
--
2.54.0.929.g9b7fa37559-goog