From: Chaosheng Qu <quchaosheng000406@163.com>
To: Steven Rostedt <rostedt@goodmis.org>
Cc: Tomas Glozar <tglozar@redhat.com>,
linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH] rtla: test that SIGINT unwinds cleanly
Date: Mon, 26 Oct 2026 14:17:18 +0800 [thread overview]
Message-ID: <179299543892.294518.9833149213443549216@163.com> (raw)
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
reply other threads:[~2026-10-26 6:19 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=179299543892.294518.9833149213443549216@163.com \
--to=quchaosheng000406@163.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=rostedt@goodmis.org \
--cc=tglozar@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox