Linux Trace Kernel
 help / color / mirror / Atom feed
* [PATCH] rtla: test that SIGINT unwinds cleanly
@ 2026-10-26  6:17 Chaosheng Qu
  0 siblings, 0 replies; only message in thread
From: Chaosheng Qu @ 2026-10-26  6:17 UTC (permalink / raw)
  To: Steven Rostedt; +Cc: Tomas Glozar, linux-trace-kernel, linux-kernel

From: Chaosheng Qu <quchaosheng000406@163.com>
Subject: [PATCH] rtla: test that SIGINT unwinds cleanly
To: Steven Rostedt <rostedt@goodmis.org>
Cc: Tomas Glozar <tglozar@redhat.com>,
    linux-trace-kernel@vger.kernel.org,
    linux-kernel@vger.kernel.org

rtla's tests only ever run the tool to completion.  Nothing exercises the
path where the tool is interrupted, which is where the trace instance
teardown can go wrong: a run that leaves an instance behind makes the next
run fail for reasons that have nothing to do with the tool, and a run that
never returns is not detected at all.

Add check_with_action(), which runs the tool like check() does but performs
an action while it is running, and always reports LEFTOVER_INSTANCES=n so
that a test can assert the instance was removed.  The tool is started with
"eval exec" so that $! is the tool itself: the action signals $RTLA_PID
directly, and timeout(1) stays the direct parent so it forwards the signal.

Then use it for osnoise and timerlat: SIGINT must make the tool unwind and
remove its instance.  check-sigint.sh looks at the process state rather
than kill -0, because a tool that has exited but has not been reaped still
answers kill -0.

Signed-off-by: Chaosheng Qu <quchaosheng000406@163.com>
---
diff --git a/tools/tracing/rtla/tests/engine.sh b/tools/tracing/rtla/tests/engine.sh
index 4287cd6..3327e16 100644
--- a/tools/tracing/rtla/tests/engine.sh
+++ b/tools/tracing/rtla/tests/engine.sh
@@ -41,6 +41,86 @@ reset_osnoise() {
 	popd >/dev/null
 }
 
+leftover_instances() {
+	# Count the trace instances rtla should have removed on exit.
+	local d count=0
+	for d in osnoise_top osnoise_hist timerlat_top timerlat_hist osnoise_trace
+	do
+		[ -d "/sys/kernel/tracing/instances/$d" ] && count=$((count + 1))
+	done
+	echo $count
+}
+
+check_with_action() {
+	# Same as "check", but run ACTION while rtla is running, so that a test
+	# can interrupt the tool mid-run.
+	# Arguments: test_name rtla_args action exit_code [expected [unexpected]]
+	# The output of ACTION is appended to rtla's output, and the number of
+	# leftover trace instances is always reported as LEFTOVER_INSTANCES=n.
+	# ACTION can use $RTLA_PID to signal the tool.
+	local test_name=$1 tested_command=$2 action=$3
+	local expected_exitcode=${4:-0}
+	local expected_output=$5 unexpected_output=$6
+	local result exitcode fail failbuf pid
+
+	ctr=$(($ctr + 1))
+	[ -z "$TEST_COUNT" ] && return
+
+	[ "$NO_RESET_OSNOISE" == 1 ] || reset_osnoise
+
+	tmpdir=$(mktemp -d)
+	pushd $tmpdir >/dev/null
+
+	# eval so that the test can use shell syntax in its arguments, and exec
+	# so that $! is the tool itself and not an intermediate shell: tests
+	# signal $RTLA_PID directly.  timeout forwards the signal to its child.
+	# The arguments are re-parsed by the same eval as in check(), so quoting
+	# behaves identically; only exec and the quoted $RTLA are added.
+	( eval "exec stdbuf -oL $TIMEOUT \"$RTLA\" $tested_command" ) > rtla.txt 2>&1 &
+	pid=$!
+	# The ACTION runs as a separate process, so RTLA_PID has to be exported
+	# or the helper scripts see it as unset.
+	export RTLA_PID=$pid
+
+	sleep "${ACTION_DELAY:-3}"
+	eval "$action" >> rtla.txt 2>&1
+
+	wait $pid
+	exitcode=$?
+	echo "LEFTOVER_INSTANCES=$(leftover_instances)" >> rtla.txt
+
+	result=$(cat rtla.txt)
+	failbuf=''
+	fail=0
+
+	if [ -n "$expected_output" ] && ! grep -qE "$expected_output" <<< "$result"
+	then
+		fail=1
+		failbuf+=$(printf "# Output match failed: \"%s\"" "$expected_output")
+		failbuf+=$'\n'
+	fi
+
+	if [ -n "$unexpected_output" ] && grep -qE "$unexpected_output" <<< "$result"
+	then
+		fail=1
+		failbuf+=$(printf "# Output non-match failed: \"%s\"" "$unexpected_output")
+		failbuf+=$'\n'
+	fi
+
+	if [ $exitcode -eq $expected_exitcode ] && [ $fail -eq 0 ]
+	then
+		echo "ok $ctr - $test_name"
+	else
+		echo "not ok $ctr - $test_name"
+		echo -n "$failbuf"
+		echo "$result" | col -b | while read line; do echo "# $line"; done
+		printf "#\n# exit code %s\n" $exitcode
+	fi
+
+	popd >/dev/null
+	rm -r $tmpdir
+}
+
 check() {
 	test_name=$0
 	tested_command=$1
diff --git a/tools/tracing/rtla/tests/osnoise.t b/tools/tracing/rtla/tests/osnoise.t
index 214fd40..df260e9 100644
--- a/tools/tracing/rtla/tests/osnoise.t
+++ b/tools/tracing/rtla/tests/osnoise.t
@@ -99,4 +99,11 @@ check_top_q_hist "with conditional continue" \
 check_top_hist "with trace output at end" \
 	"osnoise TOOL -d 1s --on-end trace" 0 "^  Saving trace to osnoise_trace.txt$"
 
+# Cleanup test: the tool must unwind on SIGINT without leaving its trace
+# instance behind.
+check_with_action "top exits on SIGINT" \
+	"osnoise top -q" \
+	"$testdir/scripts/check-sigint.sh" \
+	0 "SIGINT handled OK" "LEFTOVER_INSTANCES=[1-9]"
+
 test_end
diff --git a/tools/tracing/rtla/tests/scripts/check-sigint.sh b/tools/tracing/rtla/tests/scripts/check-sigint.sh
new file mode 100755
index 0000000..7f63424
--- /dev/null
+++ b/tools/tracing/rtla/tests/scripts/check-sigint.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Interrupt the tool with SIGINT and check that it unwinds instead of
+# hanging.  The caller reports LEFTOVER_INSTANCES separately.
+# Usage: check-sigint.sh
+# Output: "SIGINT handled OK" on success, an error otherwise.
+#
+# The tool is a child of the test shell, so once it has exited it stays
+# visible as a zombie until it is reaped -- and kill -0 still succeeds on a
+# zombie.  Check the process state instead, or a clean exit looks like a hang.
+
+pid=$RTLA_PID
+[ -n "$pid" ] || { echo "RTLA_PID not set"; exit 1; }
+
+kill -INT "$pid" 2>/dev/null || { echo "Failed to signal rtla"; exit 1; }
+
+# rtla's SIGINT handler stops tracing and lets the main loop return.  Give it
+# a few seconds before declaring it stuck.
+for _ in $(seq 30)
+do
+	[ -r "/proc/$pid/stat" ] || break
+	[ "$(awk '{print $3}' "/proc/$pid/stat" 2>/dev/null)" = "Z" ] && break
+	sleep 0.2
+done
+
+if [ -r "/proc/$pid/stat" ] && [ "$(awk '{print $3}' "/proc/$pid/stat")" != "Z" ]
+then
+	echo "rtla still running 6s after SIGINT"
+	exit 1
+fi
+
+echo "SIGINT handled OK"
diff --git a/tools/tracing/rtla/tests/timerlat.t b/tools/tracing/rtla/tests/timerlat.t
index 5116857..fe9c9da 100644
--- a/tools/tracing/rtla/tests/timerlat.t
+++ b/tools/tracing/rtla/tests/timerlat.t
@@ -153,4 +153,11 @@ else
 fi
 done
 
+# Cleanup test: the tool must unwind on SIGINT without leaving its trace
+# instance behind.
+check_with_action "top exits on SIGINT" \
+	"timerlat top -q" \
+	"$testdir/scripts/check-sigint.sh" \
+	0 "SIGINT handled OK" "LEFTOVER_INSTANCES=[1-9]"
+
 test_end


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-10-26  6:19 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-26  6:17 [PATCH] rtla: test that SIGINT unwinds cleanly Chaosheng Qu

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