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é

Reply via email to