Hi Wake,
Thanks for the help fixing my mix of kselftest_harness and ksft_() :)
Em 25/05/2026 04:57, Wake Liu escreveu:
Currently, multiple futex functional tests (wait_timeout, waitv,
wait_wouldblock) mix low-level ksft_* logging and result APIs with
the kselftest_harness.h framework. On older kernels where system calls
like futex_waitv are missing (returning -ENOSYS), this mixed usage
triggers framework inconsistencies, causing the test to fail with:
"Illegal usage of low-level ksft APIs in harness test".
Address this by completely refactoring these tests to exclusively use
the high-level kselftest_harness.h framework (gtest-like API), mapping
all low-level calls to native harness macros:
- Non-fatal assertions: Replace ksft_test_result_fail() with EXPECT_EQ()
and EXPECT_NE().
- Fatal assertions: Replace ksft_exit_fail_msg() with ASSERT_EQ() and
ASSERT_TRUE() to immediately terminate execution upon setup failure.
- Test skipping: Replace ksft_exit_skip() with the graceful SKIP() macro
combined with early runtime availability checks for sys_futex_waitv.
- Debug logging: Replace ksft_print_dbg_msg() with TH_LOG() to inherit
automatic file/line context.
- Success reporting: Remove explicit ksft_test_result_pass() calls,
deferring to automated harness completion reporting.
Additionally:
- Fix a critical SIGSEGV crash in early syscall probing logic caused by
passing a NULL pointer to inline user-space timespec conversions.
- Introduce TEST_TIMEOUT() and GET_ABS_TIMEOUT() macros in wait_timeout
to encapsulate assertions while preserving source line attribution.
- Pass test metadata (_metadata) into secondary threads to allow native
harness assertions during concurrent execution.
Signed-off-by: Wake Liu <[email protected]>
---
.../futex/functional/futex_wait_timeout.c | 101 +++++++----------
.../futex/functional/futex_wait_wouldblock.c | 40 ++++---
.../selftests/futex/functional/futex_waitv.c | 107 +++++++++---------
3 files changed, 118 insertions(+), 130 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/futex_wait_timeout.c
b/tools/testing/selftests/futex/functional/futex_wait_timeout.c
index 674dd13af421..89d6a7daeda4 100644
--- a/tools/testing/selftests/futex/functional/futex_wait_timeout.c
+++ b/tools/testing/selftests/futex/functional/futex_wait_timeout.c
[...]
-}
+#define TEST_TIMEOUT(_res, _test_name, _err) do { \
+ if ((_res) < 0 && errno == ENOSYS && (_err) != ENOSYS) { \
+ SKIP(return, "%s is not supported (ENOSYS)", _test_name); \
+ } \
+ EXPECT_EQ((_res), -1) \
+ TH_LOG("%s returned unexpected result: %d", _test_name,
(_res)); \
+ if ((_res) == -1) { \
+ EXPECT_EQ(errno, (_err)) \
+ TH_LOG("%s returned unexpected errno: %d (expected
%d)", \
+ _test_name, errno, (_err)); \
+ } \
+} while (0)
Perhaps we should always check for ETIMEDOUT and threat the only time we
check for ENOSYS here as a special case. But no strong preference.
[...]
TEST(waitv)
@@ -172,16 +157,14 @@ TEST(waitv)
int res;
For the other futex_waitv tests you call is_futex_waitv_supported(), why
don't you call for this one as well?
/* futex_waitv with CLOCK_MONOTONIC */
- if (futex_get_abs_timeout(CLOCK_MONOTONIC, &to, timeout_ns))
- ksft_test_result_error("get_time error");
+ GET_ABS_TIMEOUT(CLOCK_MONOTONIC, &to, timeout_ns);
res = futex_waitv(&waitv, 1, 0, &to, CLOCK_MONOTONIC);
- test_timeout(res, "futex_waitv monotonic", ETIMEDOUT);
+ TEST_TIMEOUT(res, "futex_waitv monotonic", ETIMEDOUT);
/* futex_waitv with CLOCK_REALTIME */
- if (futex_get_abs_timeout(CLOCK_REALTIME, &to, timeout_ns))
- ksft_test_result_error("get_time error");
+ GET_ABS_TIMEOUT(CLOCK_REALTIME, &to, timeout_ns);
res = futex_waitv(&waitv, 1, 0, &to, CLOCK_REALTIME);
- test_timeout(res, "futex_waitv realtime", ETIMEDOUT);
+ TEST_TIMEOUT(res, "futex_waitv realtime", ETIMEDOUT);
}
TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
index 9ff936ecf164..4fd517404f1f 100644
--- a/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
+++ b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
@@ -28,21 +28,26 @@
#define timeout_ns 100000
+static bool is_futex_waitv_supported(void)
+{
+ struct timespec ts = {0, 0};
+ int res = futex_waitv(NULL, 0, 0, &ts, CLOCK_MONOTONIC);
+
+ return !(res < 0 && errno == ENOSYS);
+}
+
[...]
+static bool is_futex_waitv_supported(void)
+{
+ struct timespec ts = {0, 0};
+ int res = futex_waitv(NULL, 0, 0, &ts, CLOCK_MONOTONIC);
+
+ return !(res < 0 && errno == ENOSYS);
+}
If you want to have this function in two tests, why don't you add it to
include/futex2test.h?
Also, even if not super common, we keep adding new futex features (like
syscall(__NR_futex_{wait, wake}), maybe there could be a more generic
function to skip tests if a given syscall, op or flag is not available?
André