* [PATCH 1/7] selftests/futex: Migrate futex_requeue to harness
2026-06-01 6:51 [PATCH 0/7] selftests/futex: Migrate requeue, NUMA and robust list tests to harness Wake Liu
@ 2026-06-01 6:51 ` Wake Liu
2026-07-05 19:54 ` [tip: locking/futex] " tip-bot2 for Wake Liu
2026-06-01 6:51 ` [PATCH 2/7] selftests/futex: Migrate futex_requeue_pi " Wake Liu
` (6 subsequent siblings)
7 siblings, 1 reply; 17+ messages in thread
From: Wake Liu @ 2026-06-01 6:51 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Shuah Khan, linux-kselftest
Cc: Peter Zijlstra, Darren Hart, Davidlohr Bueso, André Almeida,
Carlos Llamas, linux-kernel, wakel
Migrate futex_requeue test to the kselftest harness framework,
removing mixed legacy ksft_* API usages and ensuring proper thread joining.
Signed-off-by: Wake Liu <wakel@google.com>
---
.../futex/functional/futex_requeue.c | 32 +++++++++++++------
1 file changed, 23 insertions(+), 9 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/futex_requeue.c b/tools/testing/selftests/futex/functional/futex_requeue.c
index dcf0d5f2f312..76f0eb6756f8 100644
--- a/tools/testing/selftests/futex/functional/futex_requeue.c
+++ b/tools/testing/selftests/futex/functional/futex_requeue.c
@@ -7,6 +7,7 @@
#include <pthread.h>
#include <limits.h>
+#include <string.h>
#include "futextest.h"
#include "kselftest_harness.h"
@@ -18,13 +19,18 @@ volatile futex_t *f1;
void *waiterfn(void *arg)
{
+ struct __test_metadata *_metadata = (struct __test_metadata *)arg;
struct timespec to;
+ int res;
to.tv_sec = 0;
to.tv_nsec = timeout_ns;
- if (futex_wait(f1, *f1, &to, 0))
- printf("waiter failed errno %d\n", errno);
+ res = futex_wait(f1, *f1, &to, 0);
+ if (res) {
+ EXPECT_EQ(res, 0)
+ TH_LOG("waiter failed errno %d: %s", errno, strerror(errno));
+ }
return NULL;
}
@@ -40,12 +46,15 @@ TEST(requeue_single)
/*
* Requeue a waiter from f1 to f2, and wake f2.
*/
- ASSERT_EQ(0, pthread_create(&waiter[0], NULL, waiterfn, NULL));
+ ASSERT_EQ(pthread_create(&waiter[0], NULL, waiterfn, _metadata), 0)
+ TH_LOG("pthread_create failed");
usleep(WAKE_WAIT_US);
- EXPECT_EQ(1, futex_cmp_requeue(f1, 0, &f2, 0, 1, 0));
- EXPECT_EQ(1, futex_wake(&f2, 1, 0));
+ EXPECT_EQ(futex_cmp_requeue(f1, 0, &f2, 0, 1, 0), 1);
+ EXPECT_EQ(futex_wake(&f2, 1, 0), 1);
+
+ pthread_join(waiter[0], NULL);
}
TEST(requeue_multiple)
@@ -61,13 +70,18 @@ TEST(requeue_multiple)
* Create 10 waiters at f1. At futex_requeue, wake 3 and requeue 7.
* At futex_wake, wake INT_MAX (should be exactly 7).
*/
- for (i = 0; i < 10; i++)
- ASSERT_EQ(0, pthread_create(&waiter[i], NULL, waiterfn, NULL));
+ for (i = 0; i < 10; i++) {
+ ASSERT_EQ(pthread_create(&waiter[i], NULL, waiterfn, _metadata), 0)
+ TH_LOG("pthread_create failed for waiter %d", i);
+ }
usleep(WAKE_WAIT_US);
- EXPECT_EQ(10, futex_cmp_requeue(f1, 0, &f2, 3, 7, 0));
- EXPECT_EQ(7, futex_wake(&f2, INT_MAX, 0));
+ EXPECT_EQ(futex_cmp_requeue(f1, 0, &f2, 3, 7, 0), 10);
+ EXPECT_EQ(futex_wake(&f2, INT_MAX, 0), 7);
+
+ for (i = 0; i < 10; i++)
+ pthread_join(waiter[i], NULL);
}
TEST_HARNESS_MAIN
--
2.54.0.823.g6e5bcc1fc9-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [tip: locking/futex] selftests/futex: Migrate futex_requeue to harness
2026-06-01 6:51 ` [PATCH 1/7] selftests/futex: Migrate futex_requeue " Wake Liu
@ 2026-07-05 19:54 ` tip-bot2 for Wake Liu
0 siblings, 0 replies; 17+ messages in thread
From: tip-bot2 for Wake Liu @ 2026-07-05 19:54 UTC (permalink / raw)
To: linux-tip-commits; +Cc: Wake Liu, Thomas Gleixner, x86, linux-kernel
The following commit has been merged into the locking/futex branch of tip:
Commit-ID: d0f7df9bb778bb68a3c91c58ea8190188b46f715
Gitweb: https://git.kernel.org/tip/d0f7df9bb778bb68a3c91c58ea8190188b46f715
Author: Wake Liu <wakel@google.com>
AuthorDate: Mon, 01 Jun 2026 06:51:20
Committer: Thomas Gleixner <tglx@kernel.org>
CommitterDate: Sun, 05 Jul 2026 21:49:17 +02:00
selftests/futex: Migrate futex_requeue to harness
Migrate futex_requeue test to the kselftest harness framework, removing
mixed legacy ksft_* API usages and ensuring proper thread joining.
[ tglx: Fixup coding style ]
Signed-off-by: Wake Liu <wakel@google.com>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260601065126.3623867-2-wakel@google.com
---
tools/testing/selftests/futex/functional/futex_requeue.c | 34 ++++---
1 file changed, 24 insertions(+), 10 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/futex_requeue.c b/tools/testing/selftests/futex/functional/futex_requeue.c
index dcf0d5f..f4b8dc1 100644
--- a/tools/testing/selftests/futex/functional/futex_requeue.c
+++ b/tools/testing/selftests/futex/functional/futex_requeue.c
@@ -5,8 +5,9 @@
* futex cmp requeue test by André Almeida <andrealmeid@collabora.com>
*/
-#include <pthread.h>
#include <limits.h>
+#include <pthread.h>
+#include <string.h>
#include "futextest.h"
#include "kselftest_harness.h"
@@ -18,13 +19,18 @@ volatile futex_t *f1;
void *waiterfn(void *arg)
{
+ struct __test_metadata *_metadata = (struct __test_metadata *)arg;
struct timespec to;
+ int res;
to.tv_sec = 0;
to.tv_nsec = timeout_ns;
- if (futex_wait(f1, *f1, &to, 0))
- printf("waiter failed errno %d\n", errno);
+ res = futex_wait(f1, *f1, &to, 0);
+ if (res) {
+ EXPECT_EQ(res, 0)
+ TH_LOG("waiter failed errno %d: %s", errno, strerror(errno));
+ }
return NULL;
}
@@ -40,12 +46,15 @@ TEST(requeue_single)
/*
* Requeue a waiter from f1 to f2, and wake f2.
*/
- ASSERT_EQ(0, pthread_create(&waiter[0], NULL, waiterfn, NULL));
+ ASSERT_EQ(pthread_create(&waiter[0], NULL, waiterfn, _metadata), 0)
+ TH_LOG("pthread_create failed");
usleep(WAKE_WAIT_US);
- EXPECT_EQ(1, futex_cmp_requeue(f1, 0, &f2, 0, 1, 0));
- EXPECT_EQ(1, futex_wake(&f2, 1, 0));
+ EXPECT_EQ(futex_cmp_requeue(f1, 0, &f2, 0, 1, 0), 1);
+ EXPECT_EQ(futex_wake(&f2, 1, 0), 1);
+
+ pthread_join(waiter[0], NULL);
}
TEST(requeue_multiple)
@@ -61,13 +70,18 @@ TEST(requeue_multiple)
* Create 10 waiters at f1. At futex_requeue, wake 3 and requeue 7.
* At futex_wake, wake INT_MAX (should be exactly 7).
*/
- for (i = 0; i < 10; i++)
- ASSERT_EQ(0, pthread_create(&waiter[i], NULL, waiterfn, NULL));
+ for (i = 0; i < 10; i++) {
+ ASSERT_EQ(pthread_create(&waiter[i], NULL, waiterfn, _metadata), 0)
+ TH_LOG("pthread_create failed for waiter %d", i);
+ }
usleep(WAKE_WAIT_US);
- EXPECT_EQ(10, futex_cmp_requeue(f1, 0, &f2, 3, 7, 0));
- EXPECT_EQ(7, futex_wake(&f2, INT_MAX, 0));
+ EXPECT_EQ(futex_cmp_requeue(f1, 0, &f2, 3, 7, 0), 10);
+ EXPECT_EQ(futex_wake(&f2, INT_MAX, 0), 7);
+
+ for (i = 0; i < 10; i++)
+ pthread_join(waiter[i], NULL);
}
TEST_HARNESS_MAIN
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 2/7] selftests/futex: Migrate futex_requeue_pi to harness
2026-06-01 6:51 [PATCH 0/7] selftests/futex: Migrate requeue, NUMA and robust list tests to harness Wake Liu
2026-06-01 6:51 ` [PATCH 1/7] selftests/futex: Migrate futex_requeue " Wake Liu
@ 2026-06-01 6:51 ` Wake Liu
2026-07-05 19:54 ` [tip: locking/futex] " tip-bot2 for Wake Liu
2026-06-01 6:51 ` [PATCH 3/7] selftests/futex: Migrate futex_requeue_pi_mismatched_ops " Wake Liu
` (5 subsequent siblings)
7 siblings, 1 reply; 17+ messages in thread
From: Wake Liu @ 2026-06-01 6:51 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Shuah Khan, linux-kselftest
Cc: Peter Zijlstra, Darren Hart, Davidlohr Bueso, André Almeida,
Carlos Llamas, linux-kernel, wakel
Migrate futex_requeue_pi test to the kselftest harness framework,
removing mixed legacy ksft_* API usages and passing test metadata
to all helper threads via thread arguments.
Signed-off-by: Wake Liu <wakel@google.com>
---
.../futex/functional/futex_requeue_pi.c | 130 +++++++++---------
1 file changed, 63 insertions(+), 67 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi.c b/tools/testing/selftests/futex/functional/futex_requeue_pi.c
index 46d2858e15a8..11aada818068 100644
--- a/tools/testing/selftests/futex/functional/futex_requeue_pi.c
+++ b/tools/testing/selftests/futex/functional/futex_requeue_pi.c
@@ -43,12 +43,13 @@ futex_t f2 = FUTEX_INITIALIZER;
futex_t wake_complete = FUTEX_INITIALIZER;
struct thread_arg {
+ struct __test_metadata *_metadata;
long id;
struct timespec *timeout;
int lock;
int ret;
};
-#define THREAD_ARG_INITIALIZER { 0, NULL, 0, 0 }
+#define THREAD_ARG_INITIALIZER { NULL, 0, NULL, 0, 0 }
FIXTURE(args)
{
@@ -118,7 +119,7 @@ FIXTURE_VARIANT_ADD_TIMEOUT(5000);
FIXTURE_VARIANT_ADD_TIMEOUT(500000);
FIXTURE_VARIANT_ADD_TIMEOUT(2000000000);
-int create_rt_thread(pthread_t *pth, void*(*func)(void *), void *arg,
+int create_rt_thread(struct __test_metadata *_metadata, pthread_t *pth, void*(*func)(void *), void *arg,
int policy, int prio)
{
int ret;
@@ -129,29 +130,18 @@ int create_rt_thread(pthread_t *pth, void*(*func)(void *), void *arg,
memset(&schedp, 0, sizeof(schedp));
ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
- if (ret) {
- ksft_exit_fail_msg("pthread_attr_setinheritsched\n");
- return -1;
- }
+ ASSERT_EQ(ret, 0) TH_LOG("pthread_attr_setinheritsched failed");
ret = pthread_attr_setschedpolicy(&attr, policy);
- if (ret) {
- ksft_exit_fail_msg("pthread_attr_setschedpolicy\n");
- return -1;
- }
+ ASSERT_EQ(ret, 0) TH_LOG("pthread_attr_setschedpolicy failed");
schedp.sched_priority = prio;
ret = pthread_attr_setschedparam(&attr, &schedp);
- if (ret) {
- ksft_exit_fail_msg("pthread_attr_setschedparam\n");
- return -1;
- }
+ ASSERT_EQ(ret, 0) TH_LOG("pthread_attr_setschedparam failed");
ret = pthread_create(pth, &attr, func, arg);
- if (ret) {
- ksft_exit_fail_msg("pthread_create\n");
- return -1;
- }
+ ASSERT_EQ(ret, 0) TH_LOG("pthread_create failed");
+
return 0;
}
@@ -159,55 +149,59 @@ int create_rt_thread(pthread_t *pth, void*(*func)(void *), void *arg,
void *waiterfn(void *arg)
{
struct thread_arg *args = (struct thread_arg *)arg;
+ struct __test_metadata *_metadata = args->_metadata;
futex_t old_val;
- ksft_print_dbg_msg("Waiter %ld: running\n", args->id);
+ TH_LOG("Waiter %ld: running", args->id);
/* Each thread sleeps for a different amount of time
* This is to avoid races, because we don't lock the
- * external mutex here */
+ * external mutex here
+ */
usleep(1000 * (long)args->id);
old_val = f1;
atomic_inc(&waiters_blocked);
- ksft_print_dbg_msg("Calling futex_wait_requeue_pi: %p (%u) -> %p\n",
+ TH_LOG("Calling futex_wait_requeue_pi: %p (%u) -> %p",
&f1, f1, &f2);
args->ret = futex_wait_requeue_pi(&f1, old_val, &f2, args->timeout,
FUTEX_PRIVATE_FLAG);
- ksft_print_dbg_msg("waiter %ld woke with %d %s\n", args->id, args->ret,
+ TH_LOG("waiter %ld woke with %d %s", args->id, args->ret,
args->ret < 0 ? strerror(errno) : "");
atomic_inc(&waiters_woken);
if (args->ret < 0) {
- if (args->timeout && errno == ETIMEDOUT)
+ if (args->timeout && errno == ETIMEDOUT) {
args->ret = 0;
- else {
- ksft_exit_fail_msg("futex_wait_requeue_pi\n");
+ } else {
+ ASSERT_EQ(args->ret, 0)
+ TH_LOG("futex_wait_requeue_pi failed: %s", strerror(errno));
}
futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG);
}
futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG);
- ksft_print_dbg_msg("Waiter %ld: exiting with %d\n", args->id, args->ret);
+ TH_LOG("Waiter %ld: exiting with %d", args->id, args->ret);
pthread_exit((void *)&args->ret);
}
void *broadcast_wakerfn(void *arg)
{
struct thread_arg *args = (struct thread_arg *)arg;
+ struct __test_metadata *_metadata = args->_metadata;
int nr_requeue = INT_MAX;
int task_count = 0;
futex_t old_val;
int nr_wake = 1;
int i = 0;
- ksft_print_dbg_msg("Waker: waiting for waiters to block\n");
+ TH_LOG("Waker: waiting for waiters to block");
while (waiters_blocked.val < THREAD_MAX)
usleep(1000);
usleep(1000);
- ksft_print_dbg_msg("Waker: Calling broadcast\n");
+ TH_LOG("Waker: Calling broadcast");
if (args->lock) {
- ksft_print_dbg_msg("Calling FUTEX_LOCK_PI on mutex=%x @ %p\n", f2, &f2);
+ TH_LOG("Calling FUTEX_LOCK_PI on mutex=%x @ %p", f2, &f2);
futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG);
}
continue_requeue:
@@ -215,14 +209,16 @@ void *broadcast_wakerfn(void *arg)
args->ret = futex_cmp_requeue_pi(&f1, old_val, &f2, nr_wake, nr_requeue,
FUTEX_PRIVATE_FLAG);
if (args->ret < 0) {
- ksft_exit_fail_msg("FUTEX_CMP_REQUEUE_PI failed\n");
+ ASSERT_GE(args->ret, 0)
+ TH_LOG("FUTEX_CMP_REQUEUE_PI failed: %s", strerror(errno));
} else if (++i < MAX_WAKE_ITERS) {
task_count += args->ret;
if (task_count < THREAD_MAX - waiters_woken.val)
goto continue_requeue;
} else {
- ksft_exit_fail_msg("max broadcast iterations (%d) reached with %d/%d tasks woken or requeued\n",
- MAX_WAKE_ITERS, task_count, THREAD_MAX);
+ ASSERT_TRUE(0)
+ TH_LOG("max broadcast iterations (%d) reached with %d/%d tasks woken or requeued",
+ MAX_WAKE_ITERS, task_count, THREAD_MAX);
}
futex_wake(&wake_complete, 1, FUTEX_PRIVATE_FLAG);
@@ -233,33 +229,34 @@ void *broadcast_wakerfn(void *arg)
if (args->ret > 0)
args->ret = task_count;
- ksft_print_dbg_msg("Waker: exiting with %d\n", args->ret);
+ TH_LOG("Waker: exiting with %d", args->ret);
pthread_exit((void *)&args->ret);
}
void *signal_wakerfn(void *arg)
{
struct thread_arg *args = (struct thread_arg *)arg;
+ struct __test_metadata *_metadata = args->_metadata;
unsigned int old_val;
int nr_requeue = 0;
int task_count = 0;
int nr_wake = 1;
int i = 0;
- ksft_print_dbg_msg("Waker: waiting for waiters to block\n");
+ TH_LOG("Waker: waiting for waiters to block");
while (waiters_blocked.val < THREAD_MAX)
usleep(1000);
usleep(1000);
while (task_count < THREAD_MAX && waiters_woken.val < THREAD_MAX) {
- ksft_print_dbg_msg("task_count: %d, waiters_woken: %d\n",
+ TH_LOG("task_count: %d, waiters_woken: %d",
task_count, waiters_woken.val);
if (args->lock) {
- ksft_print_dbg_msg("Calling FUTEX_LOCK_PI on mutex=%x @ %p\n",
+ TH_LOG("Calling FUTEX_LOCK_PI on mutex=%x @ %p",
f2, &f2);
futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG);
}
- ksft_print_dbg_msg("Waker: Calling signal\n");
+ TH_LOG("Waker: Calling signal");
/* cond_signal */
old_val = f1;
args->ret = futex_cmp_requeue_pi(&f1, old_val, &f2,
@@ -267,23 +264,26 @@ void *signal_wakerfn(void *arg)
FUTEX_PRIVATE_FLAG);
if (args->ret < 0)
args->ret = -errno;
- ksft_print_dbg_msg("futex: %x\n", f2);
+ TH_LOG("futex: %x", f2);
if (args->lock) {
- ksft_print_dbg_msg("Calling FUTEX_UNLOCK_PI on mutex=%x @ %p\n",
+ TH_LOG("Calling FUTEX_UNLOCK_PI on mutex=%x @ %p",
f2, &f2);
futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG);
}
- ksft_print_dbg_msg("futex: %x\n", f2);
- if (args->ret < 0)
- ksft_exit_fail_msg("FUTEX_CMP_REQUEUE_PI failed\n");
+ TH_LOG("futex: %x", f2);
+ if (args->ret < 0) {
+ ASSERT_GE(args->ret, 0)
+ TH_LOG("FUTEX_CMP_REQUEUE_PI failed: %s", strerror(-args->ret));
+ }
task_count += args->ret;
usleep(SIGNAL_PERIOD_US);
i++;
/* we have to loop at least THREAD_MAX times */
if (i > MAX_WAKE_ITERS + THREAD_MAX) {
- ksft_exit_fail_msg("max signaling iterations (%d) reached, giving up on pending waiters.\n",
- MAX_WAKE_ITERS + THREAD_MAX);
+ ASSERT_TRUE(0)
+ TH_LOG("max signaling iterations (%d) reached, giving up on pending waiters.",
+ MAX_WAKE_ITERS + THREAD_MAX);
}
}
@@ -292,14 +292,15 @@ void *signal_wakerfn(void *arg)
if (args->ret >= 0)
args->ret = task_count;
- ksft_print_dbg_msg("Waker: exiting with %d\n", args->ret);
- ksft_print_dbg_msg("Waker: waiters_woken: %d\n", waiters_woken.val);
+ TH_LOG("Waker: exiting with %d", args->ret);
+ TH_LOG("Waker: waiters_woken: %d", waiters_woken.val);
pthread_exit((void *)&args->ret);
}
void *third_party_blocker(void *arg)
{
struct thread_arg *args = (struct thread_arg *)arg;
+ struct __test_metadata *_metadata = args->_metadata;
int ret2 = 0;
args->ret = futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG);
@@ -311,7 +312,7 @@ void *third_party_blocker(void *arg)
out:
if (args->ret || ret2)
- ksft_exit_fail_msg("third_party_blocker() futex error");
+ ASSERT_TRUE(0) TH_LOG("%s() futex error", __func__);
pthread_exit((void *)&args->ret);
}
@@ -330,20 +331,19 @@ TEST_F(args, futex_requeue_pi)
bool lock = variant->locked;
int *waiter_ret, i, ret = 0;
- ksft_print_msg(
- "\tArguments: broadcast=%d locked=%d owner=%d timeout=%ldns\n",
+ TH_LOG("Arguments: broadcast=%d locked=%d owner=%d timeout=%ldns",
broadcast, lock, third_party_owner, timeout_ns);
if (timeout_ns) {
time_t secs;
- ksft_print_dbg_msg("timeout_ns = %ld\n", timeout_ns);
+ TH_LOG("timeout_ns = %ld", timeout_ns);
ret = clock_gettime(CLOCK_MONOTONIC, &ts);
secs = (ts.tv_nsec + timeout_ns) / 1000000000;
ts.tv_nsec = ((int64_t)ts.tv_nsec + timeout_ns) % 1000000000;
ts.tv_sec += secs;
- ksft_print_dbg_msg("ts.tv_sec = %ld\n", ts.tv_sec);
- ksft_print_dbg_msg("ts.tv_nsec = %ld\n", ts.tv_nsec);
+ TH_LOG("ts.tv_sec = %ld", ts.tv_sec);
+ TH_LOG("ts.tv_nsec = %ld", ts.tv_nsec);
tsp = &ts;
}
@@ -351,27 +351,24 @@ TEST_F(args, futex_requeue_pi)
wakerfn = broadcast_wakerfn;
if (third_party_owner) {
- if (create_rt_thread(&blocker, third_party_blocker,
- (void *)&blocker_arg, SCHED_FIFO, 1)) {
- ksft_exit_fail_msg("Creating third party blocker thread failed\n");
- }
+ blocker_arg._metadata = _metadata;
+ create_rt_thread(_metadata, &blocker, third_party_blocker,
+ (void *)&blocker_arg, SCHED_FIFO, 1);
}
atomic_set(&waiters_woken, 0);
for (i = 0; i < THREAD_MAX; i++) {
+ args[i]._metadata = _metadata;
args[i].id = i;
args[i].timeout = tsp;
- ksft_print_dbg_msg("Starting thread %d\n", i);
- if (create_rt_thread(&waiter[i], waiterfn, (void *)&args[i],
- SCHED_FIFO, 1)) {
- ksft_exit_fail_msg("Creating waiting thread failed\n");
- }
+ TH_LOG("Starting thread %d", i);
+ create_rt_thread(_metadata, &waiter[i], waiterfn, (void *)&args[i],
+ SCHED_FIFO, 1);
}
+ waker_arg._metadata = _metadata;
waker_arg.lock = lock;
- if (create_rt_thread(&waker, wakerfn, (void *)&waker_arg,
- SCHED_FIFO, 1)) {
- ksft_exit_fail_msg("Creating waker thread failed\n");
- }
+ create_rt_thread(_metadata, &waker, wakerfn, (void *)&waker_arg,
+ SCHED_FIFO, 1);
/* Wait for threads to finish */
/* Store the first error or failure encountered in waiter_ret */
@@ -393,8 +390,7 @@ TEST_F(args, futex_requeue_pi)
ret = blocker_arg.ret;
}
- if (ret)
- ksft_test_result_fail("fail");
+ EXPECT_EQ(ret, 0) TH_LOG("Test failed with error code: %d", ret);
}
TEST_HARNESS_MAIN
--
2.54.0.823.g6e5bcc1fc9-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [tip: locking/futex] selftests/futex: Migrate futex_requeue_pi to harness
2026-06-01 6:51 ` [PATCH 2/7] selftests/futex: Migrate futex_requeue_pi " Wake Liu
@ 2026-07-05 19:54 ` tip-bot2 for Wake Liu
0 siblings, 0 replies; 17+ messages in thread
From: tip-bot2 for Wake Liu @ 2026-07-05 19:54 UTC (permalink / raw)
To: linux-tip-commits; +Cc: Wake Liu, Thomas Gleixner, x86, linux-kernel
The following commit has been merged into the locking/futex branch of tip:
Commit-ID: b7d837c2d49e3c62a62c14f04b38129ca6054363
Gitweb: https://git.kernel.org/tip/b7d837c2d49e3c62a62c14f04b38129ca6054363
Author: Wake Liu <wakel@google.com>
AuthorDate: Mon, 01 Jun 2026 06:51:21
Committer: Thomas Gleixner <tglx@kernel.org>
CommitterDate: Sun, 05 Jul 2026 21:49:17 +02:00
selftests/futex: Migrate futex_requeue_pi to harness
Migrate futex_requeue_pi test to the kselftest harness framework, removing
mixed legacy ksft_* API usages and passing test metadata to all helper
threads via thread arguments.
[ tglx: Fixup coding style ]
Signed-off-by: Wake Liu <wakel@google.com>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260601065126.3623867-3-wakel@google.com
---
tools/testing/selftests/futex/functional/futex_requeue_pi.c | 157 +++----
1 file changed, 79 insertions(+), 78 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi.c b/tools/testing/selftests/futex/functional/futex_requeue_pi.c
index 46d2858..65326cb 100644
--- a/tools/testing/selftests/futex/functional/futex_requeue_pi.c
+++ b/tools/testing/selftests/futex/functional/futex_requeue_pi.c
@@ -43,12 +43,13 @@ futex_t f2 = FUTEX_INITIALIZER;
futex_t wake_complete = FUTEX_INITIALIZER;
struct thread_arg {
- long id;
- struct timespec *timeout;
- int lock;
- int ret;
+ struct __test_metadata *_metadata;
+ long id;
+ struct timespec *timeout;
+ int lock;
+ int ret;
};
-#define THREAD_ARG_INITIALIZER { 0, NULL, 0, 0 }
+#define THREAD_ARG_INITIALIZER { NULL, 0, NULL, 0, 0 }
FIXTURE(args)
{
@@ -118,7 +119,7 @@ FIXTURE_VARIANT_ADD_TIMEOUT(5000);
FIXTURE_VARIANT_ADD_TIMEOUT(500000);
FIXTURE_VARIANT_ADD_TIMEOUT(2000000000);
-int create_rt_thread(pthread_t *pth, void*(*func)(void *), void *arg,
+int create_rt_thread(struct __test_metadata *_metadata, pthread_t *pth, void*(*func)(void *), void *arg,
int policy, int prio)
{
int ret;
@@ -129,29 +130,22 @@ int create_rt_thread(pthread_t *pth, void*(*func)(void *), void *arg,
memset(&schedp, 0, sizeof(schedp));
ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
- if (ret) {
- ksft_exit_fail_msg("pthread_attr_setinheritsched\n");
- return -1;
- }
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_attr_setinheritsched failed");
ret = pthread_attr_setschedpolicy(&attr, policy);
- if (ret) {
- ksft_exit_fail_msg("pthread_attr_setschedpolicy\n");
- return -1;
- }
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_attr_setschedpolicy failed");
schedp.sched_priority = prio;
ret = pthread_attr_setschedparam(&attr, &schedp);
- if (ret) {
- ksft_exit_fail_msg("pthread_attr_setschedparam\n");
- return -1;
- }
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_attr_setschedparam failed");
ret = pthread_create(pth, &attr, func, arg);
- if (ret) {
- ksft_exit_fail_msg("pthread_create\n");
- return -1;
- }
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_create failed");
+
return 0;
}
@@ -159,70 +153,76 @@ int create_rt_thread(pthread_t *pth, void*(*func)(void *), void *arg,
void *waiterfn(void *arg)
{
struct thread_arg *args = (struct thread_arg *)arg;
+ struct __test_metadata *_metadata = args->_metadata;
futex_t old_val;
- ksft_print_dbg_msg("Waiter %ld: running\n", args->id);
+ TH_LOG("Waiter %ld: running", args->id);
/* Each thread sleeps for a different amount of time
* This is to avoid races, because we don't lock the
- * external mutex here */
+ * external mutex here
+ */
usleep(1000 * (long)args->id);
old_val = f1;
atomic_inc(&waiters_blocked);
- ksft_print_dbg_msg("Calling futex_wait_requeue_pi: %p (%u) -> %p\n",
- &f1, f1, &f2);
+ TH_LOG("Calling futex_wait_requeue_pi: %p (%u) -> %p", &f1, f1, &f2);
args->ret = futex_wait_requeue_pi(&f1, old_val, &f2, args->timeout,
FUTEX_PRIVATE_FLAG);
- ksft_print_dbg_msg("waiter %ld woke with %d %s\n", args->id, args->ret,
- args->ret < 0 ? strerror(errno) : "");
+ TH_LOG("waiter %ld woke with %d %s", args->id, args->ret,
+ args->ret < 0 ? strerror(errno) : "");
atomic_inc(&waiters_woken);
if (args->ret < 0) {
- if (args->timeout && errno == ETIMEDOUT)
+ if (args->timeout && errno == ETIMEDOUT) {
args->ret = 0;
- else {
- ksft_exit_fail_msg("futex_wait_requeue_pi\n");
+ } else {
+ ASSERT_EQ(args->ret, 0)
+ TH_LOG("futex_wait_requeue_pi failed: %s", strerror(errno));
}
futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG);
}
futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG);
- ksft_print_dbg_msg("Waiter %ld: exiting with %d\n", args->id, args->ret);
+ TH_LOG("Waiter %ld: exiting with %d", args->id, args->ret);
pthread_exit((void *)&args->ret);
}
void *broadcast_wakerfn(void *arg)
{
struct thread_arg *args = (struct thread_arg *)arg;
+ struct __test_metadata *_metadata = args->_metadata;
int nr_requeue = INT_MAX;
int task_count = 0;
futex_t old_val;
int nr_wake = 1;
int i = 0;
- ksft_print_dbg_msg("Waker: waiting for waiters to block\n");
+ TH_LOG("Waker: waiting for waiters to block");
while (waiters_blocked.val < THREAD_MAX)
usleep(1000);
usleep(1000);
- ksft_print_dbg_msg("Waker: Calling broadcast\n");
+ TH_LOG("Waker: Calling broadcast");
if (args->lock) {
- ksft_print_dbg_msg("Calling FUTEX_LOCK_PI on mutex=%x @ %p\n", f2, &f2);
+ TH_LOG("Calling FUTEX_LOCK_PI on mutex=%x @ %p", f2, &f2);
futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG);
}
continue_requeue:
old_val = f1;
args->ret = futex_cmp_requeue_pi(&f1, old_val, &f2, nr_wake, nr_requeue,
- FUTEX_PRIVATE_FLAG);
+ FUTEX_PRIVATE_FLAG);
if (args->ret < 0) {
- ksft_exit_fail_msg("FUTEX_CMP_REQUEUE_PI failed\n");
+ ASSERT_GE(args->ret, 0)
+ TH_LOG("FUTEX_CMP_REQUEUE_PI failed: %s", strerror(errno));
} else if (++i < MAX_WAKE_ITERS) {
task_count += args->ret;
if (task_count < THREAD_MAX - waiters_woken.val)
goto continue_requeue;
} else {
- ksft_exit_fail_msg("max broadcast iterations (%d) reached with %d/%d tasks woken or requeued\n",
- MAX_WAKE_ITERS, task_count, THREAD_MAX);
+ ASSERT_TRUE(0) {
+ TH_LOG("max broadcast iterations (%d) reached with %d/%d tasks woken or requeued",
+ MAX_WAKE_ITERS, task_count, THREAD_MAX);
+ }
}
futex_wake(&wake_complete, 1, FUTEX_PRIVATE_FLAG);
@@ -233,33 +233,33 @@ void *broadcast_wakerfn(void *arg)
if (args->ret > 0)
args->ret = task_count;
- ksft_print_dbg_msg("Waker: exiting with %d\n", args->ret);
+ TH_LOG("Waker: exiting with %d", args->ret);
pthread_exit((void *)&args->ret);
}
void *signal_wakerfn(void *arg)
{
struct thread_arg *args = (struct thread_arg *)arg;
+ struct __test_metadata *_metadata = args->_metadata;
unsigned int old_val;
int nr_requeue = 0;
int task_count = 0;
int nr_wake = 1;
int i = 0;
- ksft_print_dbg_msg("Waker: waiting for waiters to block\n");
+ TH_LOG("Waker: waiting for waiters to block");
while (waiters_blocked.val < THREAD_MAX)
usleep(1000);
usleep(1000);
while (task_count < THREAD_MAX && waiters_woken.val < THREAD_MAX) {
- ksft_print_dbg_msg("task_count: %d, waiters_woken: %d\n",
+ TH_LOG("task_count: %d, waiters_woken: %d",
task_count, waiters_woken.val);
if (args->lock) {
- ksft_print_dbg_msg("Calling FUTEX_LOCK_PI on mutex=%x @ %p\n",
- f2, &f2);
+ TH_LOG("Calling FUTEX_LOCK_PI on mutex=%x @ %p", f2, &f2);
futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG);
}
- ksft_print_dbg_msg("Waker: Calling signal\n");
+ TH_LOG("Waker: Calling signal");
/* cond_signal */
old_val = f1;
args->ret = futex_cmp_requeue_pi(&f1, old_val, &f2,
@@ -267,23 +267,27 @@ void *signal_wakerfn(void *arg)
FUTEX_PRIVATE_FLAG);
if (args->ret < 0)
args->ret = -errno;
- ksft_print_dbg_msg("futex: %x\n", f2);
+ TH_LOG("futex: %x", f2);
if (args->lock) {
- ksft_print_dbg_msg("Calling FUTEX_UNLOCK_PI on mutex=%x @ %p\n",
+ TH_LOG("Calling FUTEX_UNLOCK_PI on mutex=%x @ %p",
f2, &f2);
futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG);
}
- ksft_print_dbg_msg("futex: %x\n", f2);
- if (args->ret < 0)
- ksft_exit_fail_msg("FUTEX_CMP_REQUEUE_PI failed\n");
+ TH_LOG("futex: %x", f2);
+ if (args->ret < 0) {
+ ASSERT_GE(args->ret, 0)
+ TH_LOG("FUTEX_CMP_REQUEUE_PI failed: %s", strerror(-args->ret));
+ }
task_count += args->ret;
usleep(SIGNAL_PERIOD_US);
i++;
/* we have to loop at least THREAD_MAX times */
if (i > MAX_WAKE_ITERS + THREAD_MAX) {
- ksft_exit_fail_msg("max signaling iterations (%d) reached, giving up on pending waiters.\n",
- MAX_WAKE_ITERS + THREAD_MAX);
+ ASSERT_TRUE(0) {
+ TH_LOG("max signaling iterations (%d) reached, giving up on pending waiters.",
+ MAX_WAKE_ITERS + THREAD_MAX);
+ }
}
}
@@ -292,14 +296,15 @@ void *signal_wakerfn(void *arg)
if (args->ret >= 0)
args->ret = task_count;
- ksft_print_dbg_msg("Waker: exiting with %d\n", args->ret);
- ksft_print_dbg_msg("Waker: waiters_woken: %d\n", waiters_woken.val);
+ TH_LOG("Waker: exiting with %d", args->ret);
+ TH_LOG("Waker: waiters_woken: %d", waiters_woken.val);
pthread_exit((void *)&args->ret);
}
void *third_party_blocker(void *arg)
{
struct thread_arg *args = (struct thread_arg *)arg;
+ struct __test_metadata *_metadata = args->_metadata;
int ret2 = 0;
args->ret = futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG);
@@ -310,8 +315,10 @@ void *third_party_blocker(void *arg)
ret2 = futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG);
out:
- if (args->ret || ret2)
- ksft_exit_fail_msg("third_party_blocker() futex error");
+ if (args->ret || ret2) {
+ ASSERT_TRUE(0)
+ TH_LOG("%s() futex error", __func__);
+ }
pthread_exit((void *)&args->ret);
}
@@ -330,20 +337,19 @@ TEST_F(args, futex_requeue_pi)
bool lock = variant->locked;
int *waiter_ret, i, ret = 0;
- ksft_print_msg(
- "\tArguments: broadcast=%d locked=%d owner=%d timeout=%ldns\n",
+ TH_LOG("Arguments: broadcast=%d locked=%d owner=%d timeout=%ldns",
broadcast, lock, third_party_owner, timeout_ns);
if (timeout_ns) {
time_t secs;
- ksft_print_dbg_msg("timeout_ns = %ld\n", timeout_ns);
+ TH_LOG("timeout_ns = %ld", timeout_ns);
ret = clock_gettime(CLOCK_MONOTONIC, &ts);
secs = (ts.tv_nsec + timeout_ns) / 1000000000;
ts.tv_nsec = ((int64_t)ts.tv_nsec + timeout_ns) % 1000000000;
ts.tv_sec += secs;
- ksft_print_dbg_msg("ts.tv_sec = %ld\n", ts.tv_sec);
- ksft_print_dbg_msg("ts.tv_nsec = %ld\n", ts.tv_nsec);
+ TH_LOG("ts.tv_sec = %ld", ts.tv_sec);
+ TH_LOG("ts.tv_nsec = %ld", ts.tv_nsec);
tsp = &ts;
}
@@ -351,34 +357,29 @@ TEST_F(args, futex_requeue_pi)
wakerfn = broadcast_wakerfn;
if (third_party_owner) {
- if (create_rt_thread(&blocker, third_party_blocker,
- (void *)&blocker_arg, SCHED_FIFO, 1)) {
- ksft_exit_fail_msg("Creating third party blocker thread failed\n");
- }
+ blocker_arg._metadata = _metadata;
+ create_rt_thread(_metadata, &blocker, third_party_blocker,
+ (void *)&blocker_arg, SCHED_FIFO, 1);
}
atomic_set(&waiters_woken, 0);
for (i = 0; i < THREAD_MAX; i++) {
+ args[i]._metadata = _metadata;
args[i].id = i;
args[i].timeout = tsp;
- ksft_print_dbg_msg("Starting thread %d\n", i);
- if (create_rt_thread(&waiter[i], waiterfn, (void *)&args[i],
- SCHED_FIFO, 1)) {
- ksft_exit_fail_msg("Creating waiting thread failed\n");
- }
+ TH_LOG("Starting thread %d", i);
+ create_rt_thread(_metadata, &waiter[i], waiterfn, (void *)&args[i],
+ SCHED_FIFO, 1);
}
+ waker_arg._metadata = _metadata;
waker_arg.lock = lock;
- if (create_rt_thread(&waker, wakerfn, (void *)&waker_arg,
- SCHED_FIFO, 1)) {
- ksft_exit_fail_msg("Creating waker thread failed\n");
- }
+ create_rt_thread(_metadata, &waker, wakerfn, (void *)&waker_arg, SCHED_FIFO, 1);
/* Wait for threads to finish */
/* Store the first error or failure encountered in waiter_ret */
waiter_ret = &args[0].ret;
for (i = 0; i < THREAD_MAX; i++)
- pthread_join(waiter[i],
- *waiter_ret ? NULL : (void **)&waiter_ret);
+ pthread_join(waiter[i], *waiter_ret ? NULL : (void **)&waiter_ret);
if (third_party_owner)
pthread_join(blocker, NULL);
@@ -393,8 +394,8 @@ TEST_F(args, futex_requeue_pi)
ret = blocker_arg.ret;
}
- if (ret)
- ksft_test_result_fail("fail");
+ EXPECT_EQ(ret, 0)
+ TH_LOG("Test failed with error code: %d", ret);
}
TEST_HARNESS_MAIN
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 3/7] selftests/futex: Migrate futex_requeue_pi_mismatched_ops to harness
2026-06-01 6:51 [PATCH 0/7] selftests/futex: Migrate requeue, NUMA and robust list tests to harness Wake Liu
2026-06-01 6:51 ` [PATCH 1/7] selftests/futex: Migrate futex_requeue " Wake Liu
2026-06-01 6:51 ` [PATCH 2/7] selftests/futex: Migrate futex_requeue_pi " Wake Liu
@ 2026-06-01 6:51 ` Wake Liu
2026-07-05 19:54 ` [tip: locking/futex] " tip-bot2 for Wake Liu
2026-06-01 6:51 ` [PATCH 4/7] selftests/futex: Migrate futex_requeue_pi_signal_restart " Wake Liu
` (4 subsequent siblings)
7 siblings, 1 reply; 17+ messages in thread
From: Wake Liu @ 2026-06-01 6:51 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Shuah Khan, linux-kselftest
Cc: Peter Zijlstra, Darren Hart, Davidlohr Bueso, André Almeida,
Carlos Llamas, linux-kernel, wakel
Migrate futex_requeue_pi_mismatched_ops test to the kselftest harness framework,
removing mixed legacy ksft_* API usages and passing test metadata to helper thread.
Signed-off-by: Wake Liu <wakel@google.com>
---
.../futex_requeue_pi_mismatched_ops.c | 39 +++++++++++--------
1 file changed, 23 insertions(+), 16 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c b/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c
index f686e605359c..c55eadd261da 100644
--- a/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c
+++ b/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c
@@ -29,14 +29,17 @@
futex_t f1 = FUTEX_INITIALIZER;
futex_t f2 = FUTEX_INITIALIZER;
-int child_ret = 0;
+int child_ret;
void *blocking_child(void *arg)
{
+ struct __test_metadata *_metadata = (struct __test_metadata *)arg;
+
child_ret = futex_wait(&f1, f1, NULL, FUTEX_PRIVATE_FLAG);
if (child_ret < 0) {
child_ret = -errno;
- ksft_exit_fail_msg("futex_wait\n");
+ ASSERT_EQ(child_ret, 0)
+ TH_LOG("futex_wait failed: %s", strerror(errno));
}
return (void *)&child_ret;
}
@@ -46,8 +49,8 @@ TEST(requeue_pi_mismatched_ops)
pthread_t child;
int ret;
- if (pthread_create(&child, NULL, blocking_child, NULL))
- ksft_exit_fail_msg("pthread_create\n");
+ ASSERT_EQ(pthread_create(&child, NULL, blocking_child, _metadata), 0)
+ TH_LOG("pthread_create failed");
/* Allow the child to block in the kernel. */
sleep(1);
@@ -67,27 +70,31 @@ TEST(requeue_pi_mismatched_ops)
* FUTEX_WAKE.
*/
ret = futex_wake(&f1, 1, FUTEX_PRIVATE_FLAG);
- if (ret == 1)
+ if (ret == 1) {
ret = 0;
- else if (ret < 0)
- ksft_exit_fail_msg("futex_wake\n");
- else
- ksft_exit_fail_msg("futex_wake did not wake the child\n");
+ } else if (ret < 0) {
+ ASSERT_GE(ret, 0)
+ TH_LOG("futex_wake failed: %s", strerror(errno));
+ } else {
+ ASSERT_TRUE(0)
+ TH_LOG("futex_wake did not wake the child");
+ }
} else {
- ksft_exit_fail_msg("futex_cmp_requeue_pi\n");
+ ASSERT_TRUE(0)
+ TH_LOG("futex_cmp_requeue_pi failed with unexpected errno: %s", strerror(errno));
}
} else if (ret > 0) {
- ksft_test_result_fail("futex_cmp_requeue_pi failed to detect the mismatch\n");
+ EXPECT_EQ(ret, 0)
+ TH_LOG("futex_cmp_requeue_pi failed to detect the mismatch");
} else {
- ksft_exit_fail_msg("futex_cmp_requeue_pi found no waiters\n");
+ ASSERT_TRUE(0)
+ TH_LOG("futex_cmp_requeue_pi found no waiters");
}
pthread_join(child, NULL);
- if (!ret && !child_ret)
- ksft_test_result_pass("futex_requeue_pi_mismatched_ops passed\n");
- else
- ksft_test_result_pass("futex_requeue_pi_mismatched_ops failed\n");
+ EXPECT_EQ(ret, 0) TH_LOG("Test failed: ret=%d", ret);
+ EXPECT_EQ(child_ret, 0) TH_LOG("Child failed: child_ret=%d", child_ret);
}
TEST_HARNESS_MAIN
--
2.54.0.823.g6e5bcc1fc9-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [tip: locking/futex] selftests/futex: Migrate futex_requeue_pi_mismatched_ops to harness
2026-06-01 6:51 ` [PATCH 3/7] selftests/futex: Migrate futex_requeue_pi_mismatched_ops " Wake Liu
@ 2026-07-05 19:54 ` tip-bot2 for Wake Liu
0 siblings, 0 replies; 17+ messages in thread
From: tip-bot2 for Wake Liu @ 2026-07-05 19:54 UTC (permalink / raw)
To: linux-tip-commits; +Cc: Wake Liu, Thomas Gleixner, x86, linux-kernel
The following commit has been merged into the locking/futex branch of tip:
Commit-ID: 4559deb7382861b5e920bbccdf62c470384ab0ac
Gitweb: https://git.kernel.org/tip/4559deb7382861b5e920bbccdf62c470384ab0ac
Author: Wake Liu <wakel@google.com>
AuthorDate: Mon, 01 Jun 2026 06:51:22
Committer: Thomas Gleixner <tglx@kernel.org>
CommitterDate: Sun, 05 Jul 2026 21:49:18 +02:00
selftests/futex: Migrate futex_requeue_pi_mismatched_ops to harness
Migrate futex_requeue_pi_mismatched_ops test to the kselftest harness
framework, removing mixed legacy ksft_* API usages and passing test
metadata to helper thread.
[ tglx: Fixup coding style ]
Signed-off-by: Wake Liu <wakel@google.com>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260601065126.3623867-4-wakel@google.com
---
tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c | 41 +++++++++++++++++++++++++----------------
1 file changed, 25 insertions(+), 16 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c b/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c
index f686e60..35bb8a8 100644
--- a/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c
+++ b/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c
@@ -29,14 +29,17 @@
futex_t f1 = FUTEX_INITIALIZER;
futex_t f2 = FUTEX_INITIALIZER;
-int child_ret = 0;
+int child_ret;
void *blocking_child(void *arg)
{
+ struct __test_metadata *_metadata = (struct __test_metadata *)arg;
+
child_ret = futex_wait(&f1, f1, NULL, FUTEX_PRIVATE_FLAG);
if (child_ret < 0) {
child_ret = -errno;
- ksft_exit_fail_msg("futex_wait\n");
+ ASSERT_EQ(child_ret, 0)
+ TH_LOG("futex_wait failed: %s", strerror(errno));
}
return (void *)&child_ret;
}
@@ -46,8 +49,8 @@ TEST(requeue_pi_mismatched_ops)
pthread_t child;
int ret;
- if (pthread_create(&child, NULL, blocking_child, NULL))
- ksft_exit_fail_msg("pthread_create\n");
+ ASSERT_EQ(pthread_create(&child, NULL, blocking_child, _metadata), 0)
+ TH_LOG("pthread_create failed");
/* Allow the child to block in the kernel. */
sleep(1);
@@ -67,27 +70,33 @@ TEST(requeue_pi_mismatched_ops)
* FUTEX_WAKE.
*/
ret = futex_wake(&f1, 1, FUTEX_PRIVATE_FLAG);
- if (ret == 1)
+ if (ret == 1) {
ret = 0;
- else if (ret < 0)
- ksft_exit_fail_msg("futex_wake\n");
- else
- ksft_exit_fail_msg("futex_wake did not wake the child\n");
+ } else if (ret < 0) {
+ ASSERT_GE(ret, 0)
+ TH_LOG("futex_wake failed: %s", strerror(errno));
+ } else {
+ ASSERT_TRUE(0)
+ TH_LOG("futex_wake did not wake the child");
+ }
} else {
- ksft_exit_fail_msg("futex_cmp_requeue_pi\n");
+ ASSERT_TRUE(0)
+ TH_LOG("futex_cmp_requeue_pi failed with unexpected errno: %s", strerror(errno));
}
} else if (ret > 0) {
- ksft_test_result_fail("futex_cmp_requeue_pi failed to detect the mismatch\n");
+ EXPECT_EQ(ret, 0)
+ TH_LOG("futex_cmp_requeue_pi failed to detect the mismatch");
} else {
- ksft_exit_fail_msg("futex_cmp_requeue_pi found no waiters\n");
+ ASSERT_TRUE(0)
+ TH_LOG("futex_cmp_requeue_pi found no waiters");
}
pthread_join(child, NULL);
- if (!ret && !child_ret)
- ksft_test_result_pass("futex_requeue_pi_mismatched_ops passed\n");
- else
- ksft_test_result_pass("futex_requeue_pi_mismatched_ops failed\n");
+ EXPECT_EQ(ret, 0)
+ TH_LOG("Test failed: ret=%d", ret);
+ EXPECT_EQ(child_ret, 0)
+ TH_LOG("Child failed: child_ret=%d", child_ret);
}
TEST_HARNESS_MAIN
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 4/7] selftests/futex: Migrate futex_requeue_pi_signal_restart to harness
2026-06-01 6:51 [PATCH 0/7] selftests/futex: Migrate requeue, NUMA and robust list tests to harness Wake Liu
` (2 preceding siblings ...)
2026-06-01 6:51 ` [PATCH 3/7] selftests/futex: Migrate futex_requeue_pi_mismatched_ops " Wake Liu
@ 2026-06-01 6:51 ` Wake Liu
2026-07-05 19:54 ` [tip: locking/futex] " tip-bot2 for Wake Liu
2026-06-01 6:51 ` [PATCH 5/7] selftests/futex: Migrate futex_numa_mpol " Wake Liu
` (3 subsequent siblings)
7 siblings, 1 reply; 17+ messages in thread
From: Wake Liu @ 2026-06-01 6:51 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Shuah Khan, linux-kselftest
Cc: Peter Zijlstra, Darren Hart, Davidlohr Bueso, André Almeida,
Carlos Llamas, linux-kernel, wakel
Migrate futex_requeue_pi_signal_restart test to the kselftest harness framework,
removing mixed legacy ksft_* API usages and ensuring proper thread joining.
Signed-off-by: Wake Liu <wakel@google.com>
---
.../futex_requeue_pi_signal_restart.c | 67 +++++++++----------
1 file changed, 31 insertions(+), 36 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c b/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c
index a18ccae73eb1..e301beb4b202 100644
--- a/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c
+++ b/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c
@@ -35,9 +35,9 @@ futex_t f1 = FUTEX_INITIALIZER;
futex_t f2 = FUTEX_INITIALIZER;
atomic_t requeued = ATOMIC_INITIALIZER;
-int waiter_ret = 0;
+int waiter_ret;
-int create_rt_thread(pthread_t *pth, void*(*func)(void *), void *arg,
+int create_rt_thread(struct __test_metadata *_metadata, pthread_t *pth, void*(*func)(void *), void *arg,
int policy, int prio)
{
struct sched_param schedp;
@@ -48,45 +48,43 @@ int create_rt_thread(pthread_t *pth, void*(*func)(void *), void *arg,
memset(&schedp, 0, sizeof(schedp));
ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
- if (ret)
- ksft_exit_fail_msg("pthread_attr_setinheritsched\n");
+ ASSERT_EQ(ret, 0) TH_LOG("pthread_attr_setinheritsched failed");
ret = pthread_attr_setschedpolicy(&attr, policy);
- if (ret)
- ksft_exit_fail_msg("pthread_attr_setschedpolicy\n");
+ ASSERT_EQ(ret, 0) TH_LOG("pthread_attr_setschedpolicy failed");
schedp.sched_priority = prio;
ret = pthread_attr_setschedparam(&attr, &schedp);
- if (ret)
- ksft_exit_fail_msg("pthread_attr_setschedparam\n");
+ ASSERT_EQ(ret, 0) TH_LOG("pthread_attr_setschedparam failed");
ret = pthread_create(pth, &attr, func, arg);
- if (ret)
- ksft_exit_fail_msg("pthread_create\n");
+ ASSERT_EQ(ret, 0) TH_LOG("pthread_create failed");
return 0;
}
void handle_signal(int signo)
{
- ksft_print_dbg_msg("signal received %s requeue\n",
- requeued.val ? "after" : "prior to");
+ printf("INFO: signal received %s requeue\n",
+ requeued.val ? "after" : "prior to");
}
void *waiterfn(void *arg)
{
+ struct __test_metadata *_metadata = (struct __test_metadata *)arg;
unsigned int old_val;
int res;
- ksft_print_dbg_msg("Waiter running\n");
- ksft_print_dbg_msg("Calling FUTEX_LOCK_PI on f2=%x @ %p\n", f2, &f2);
+ TH_LOG("Waiter running");
+ TH_LOG("Calling FUTEX_LOCK_PI on f2=%x @ %p", f2, &f2);
old_val = f1;
res = futex_wait_requeue_pi(&f1, old_val, &(f2), NULL,
FUTEX_PRIVATE_FLAG);
if (!requeued.val || errno != EWOULDBLOCK) {
- ksft_test_result_fail("unexpected return from futex_wait_requeue_pi: %d (%s)\n",
- res, strerror(errno));
- ksft_print_dbg_msg("w2:futex: %x\n", f2);
+ EXPECT_TRUE(0)
+ TH_LOG("unexpected return from futex_wait_requeue_pi: %d (%s)",
+ res, strerror(errno));
+ TH_LOG("w2:futex: %x", f2);
if (!res)
futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG);
}
@@ -94,7 +92,6 @@ void *waiterfn(void *arg)
pthread_exit(NULL);
}
-
TEST(futex_requeue_pi_signal_restart)
{
unsigned int old_val;
@@ -105,19 +102,16 @@ TEST(futex_requeue_pi_signal_restart)
sa.sa_handler = handle_signal;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
- if (sigaction(SIGUSR1, &sa, NULL))
- ksft_exit_fail_msg("sigaction\n");
+ ASSERT_EQ(sigaction(SIGUSR1, &sa, NULL), 0) TH_LOG("sigaction failed");
- ksft_print_dbg_msg("m1:f2: %x\n", f2);
- ksft_print_dbg_msg("Creating waiter\n");
- res = create_rt_thread(&waiter, waiterfn, NULL, SCHED_FIFO, 1);
- if (res)
- ksft_exit_fail_msg("Creating waiting thread failed");
+ TH_LOG("m1:f2: %x", f2);
+ TH_LOG("Creating waiter");
+ create_rt_thread(_metadata, &waiter, waiterfn, _metadata, SCHED_FIFO, 1);
- ksft_print_dbg_msg("Calling FUTEX_LOCK_PI on f2=%x @ %p\n", f2, &f2);
- ksft_print_dbg_msg("m2:f2: %x\n", f2);
+ TH_LOG("Calling FUTEX_LOCK_PI on f2=%x @ %p", f2, &f2);
+ TH_LOG("m2:f2: %x", f2);
futex_lock_pi(&f2, 0, 0, FUTEX_PRIVATE_FLAG);
- ksft_print_dbg_msg("m3:f2: %x\n", f2);
+ TH_LOG("m3:f2: %x", f2);
while (1) {
/*
@@ -125,11 +119,11 @@ TEST(futex_requeue_pi_signal_restart)
* restart futex_wait_requeue_pi() in the kernel. Wait for the
* waiter to block on f1 again.
*/
- ksft_print_dbg_msg("Issuing SIGUSR1 to waiter\n");
+ TH_LOG("Issuing SIGUSR1 to waiter");
pthread_kill(waiter, SIGUSR1);
usleep(DELAY_US);
- ksft_print_dbg_msg("Requeueing waiter via FUTEX_CMP_REQUEUE_PI\n");
+ TH_LOG("Requeueing waiter via FUTEX_CMP_REQUEUE_PI");
old_val = f1;
res = futex_cmp_requeue_pi(&f1, old_val, &(f2), 1, 0,
FUTEX_PRIVATE_FLAG);
@@ -143,10 +137,11 @@ TEST(futex_requeue_pi_signal_restart)
atomic_set(&requeued, 1);
break;
} else if (res < 0) {
- ksft_exit_fail_msg("FUTEX_CMP_REQUEUE_PI failed\n");
+ ASSERT_GE(res, 0)
+ TH_LOG("FUTEX_CMP_REQUEUE_PI failed: %s", strerror(errno));
}
}
- ksft_print_dbg_msg("m4:f2: %x\n", f2);
+ TH_LOG("m4:f2: %x", f2);
/*
* Signal the waiter after requeue, waiter should return from
@@ -154,14 +149,14 @@ TEST(futex_requeue_pi_signal_restart)
* futex_unlock_pi() can't happen before the signal wakeup is detected
* in the kernel.
*/
- ksft_print_dbg_msg("Issuing SIGUSR1 to waiter\n");
+ TH_LOG("Issuing SIGUSR1 to waiter");
pthread_kill(waiter, SIGUSR1);
- ksft_print_dbg_msg("Waiting for waiter to return\n");
+ TH_LOG("Waiting for waiter to return");
pthread_join(waiter, NULL);
- ksft_print_dbg_msg("Calling FUTEX_UNLOCK_PI on mutex=%x @ %p\n", f2, &f2);
+ TH_LOG("Calling FUTEX_UNLOCK_PI on mutex=%x @ %p", f2, &f2);
futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG);
- ksft_print_dbg_msg("m5:f2: %x\n", f2);
+ TH_LOG("m5:f2: %x", f2);
}
TEST_HARNESS_MAIN
--
2.54.0.823.g6e5bcc1fc9-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [tip: locking/futex] selftests/futex: Migrate futex_requeue_pi_signal_restart to harness
2026-06-01 6:51 ` [PATCH 4/7] selftests/futex: Migrate futex_requeue_pi_signal_restart " Wake Liu
@ 2026-07-05 19:54 ` tip-bot2 for Wake Liu
0 siblings, 0 replies; 17+ messages in thread
From: tip-bot2 for Wake Liu @ 2026-07-05 19:54 UTC (permalink / raw)
To: linux-tip-commits; +Cc: Wake Liu, Thomas Gleixner, x86, linux-kernel
The following commit has been merged into the locking/futex branch of tip:
Commit-ID: 7fe733f11215ac7eb308ad2e57a2b2279ce9f303
Gitweb: https://git.kernel.org/tip/7fe733f11215ac7eb308ad2e57a2b2279ce9f303
Author: Wake Liu <wakel@google.com>
AuthorDate: Mon, 01 Jun 2026 06:51:23
Committer: Thomas Gleixner <tglx@kernel.org>
CommitterDate: Sun, 05 Jul 2026 21:49:18 +02:00
selftests/futex: Migrate futex_requeue_pi_signal_restart to harness
Migrate futex_requeue_pi_signal_restart test to the kselftest harness
framework, removing mixed legacy ksft_* API usages and ensuring proper
thread joining.
[ tglx: Fixup coding style ]
Signed-off-by: Wake Liu <wakel@google.com>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260601065126.3623867-5-wakel@google.com
---
tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c | 74 +++++++++++++++++++++++++++++++++++-----------------------------------
1 file changed, 37 insertions(+), 37 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c b/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c
index a18ccae..4933612 100644
--- a/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c
+++ b/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c
@@ -35,10 +35,10 @@ futex_t f1 = FUTEX_INITIALIZER;
futex_t f2 = FUTEX_INITIALIZER;
atomic_t requeued = ATOMIC_INITIALIZER;
-int waiter_ret = 0;
+int waiter_ret;
-int create_rt_thread(pthread_t *pth, void*(*func)(void *), void *arg,
- int policy, int prio)
+int create_rt_thread(struct __test_metadata *_metadata, pthread_t *pth, void*(*func)(void *),
+ void *arg, int policy, int prio)
{
struct sched_param schedp;
pthread_attr_t attr;
@@ -48,45 +48,47 @@ int create_rt_thread(pthread_t *pth, void*(*func)(void *), void *arg,
memset(&schedp, 0, sizeof(schedp));
ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
- if (ret)
- ksft_exit_fail_msg("pthread_attr_setinheritsched\n");
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_attr_setinheritsched failed");
ret = pthread_attr_setschedpolicy(&attr, policy);
- if (ret)
- ksft_exit_fail_msg("pthread_attr_setschedpolicy\n");
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_attr_setschedpolicy failed");
schedp.sched_priority = prio;
ret = pthread_attr_setschedparam(&attr, &schedp);
- if (ret)
- ksft_exit_fail_msg("pthread_attr_setschedparam\n");
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_attr_setschedparam failed");
ret = pthread_create(pth, &attr, func, arg);
- if (ret)
- ksft_exit_fail_msg("pthread_create\n");
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_create failed");
return 0;
}
void handle_signal(int signo)
{
- ksft_print_dbg_msg("signal received %s requeue\n",
- requeued.val ? "after" : "prior to");
+ printf("INFO: signal received %s requeue\n", requeued.val ? "after" : "prior to");
}
void *waiterfn(void *arg)
{
+ struct __test_metadata *_metadata = (struct __test_metadata *)arg;
unsigned int old_val;
int res;
- ksft_print_dbg_msg("Waiter running\n");
- ksft_print_dbg_msg("Calling FUTEX_LOCK_PI on f2=%x @ %p\n", f2, &f2);
+ TH_LOG("Waiter running");
+ TH_LOG("Calling FUTEX_LOCK_PI on f2=%x @ %p", f2, &f2);
old_val = f1;
res = futex_wait_requeue_pi(&f1, old_val, &(f2), NULL,
FUTEX_PRIVATE_FLAG);
if (!requeued.val || errno != EWOULDBLOCK) {
- ksft_test_result_fail("unexpected return from futex_wait_requeue_pi: %d (%s)\n",
- res, strerror(errno));
- ksft_print_dbg_msg("w2:futex: %x\n", f2);
+ EXPECT_TRUE(0) {
+ TH_LOG("unexpected return from futex_wait_requeue_pi: %d (%s)",
+ res, strerror(errno));
+ }
+ TH_LOG("w2:futex: %x", f2);
if (!res)
futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG);
}
@@ -94,7 +96,6 @@ void *waiterfn(void *arg)
pthread_exit(NULL);
}
-
TEST(futex_requeue_pi_signal_restart)
{
unsigned int old_val;
@@ -105,19 +106,17 @@ TEST(futex_requeue_pi_signal_restart)
sa.sa_handler = handle_signal;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
- if (sigaction(SIGUSR1, &sa, NULL))
- ksft_exit_fail_msg("sigaction\n");
+ ASSERT_EQ(sigaction(SIGUSR1, &sa, NULL), 0)
+ TH_LOG("sigaction failed");
- ksft_print_dbg_msg("m1:f2: %x\n", f2);
- ksft_print_dbg_msg("Creating waiter\n");
- res = create_rt_thread(&waiter, waiterfn, NULL, SCHED_FIFO, 1);
- if (res)
- ksft_exit_fail_msg("Creating waiting thread failed");
+ TH_LOG("m1:f2: %x", f2);
+ TH_LOG("Creating waiter");
+ create_rt_thread(_metadata, &waiter, waiterfn, _metadata, SCHED_FIFO, 1);
- ksft_print_dbg_msg("Calling FUTEX_LOCK_PI on f2=%x @ %p\n", f2, &f2);
- ksft_print_dbg_msg("m2:f2: %x\n", f2);
+ TH_LOG("Calling FUTEX_LOCK_PI on f2=%x @ %p", f2, &f2);
+ TH_LOG("m2:f2: %x", f2);
futex_lock_pi(&f2, 0, 0, FUTEX_PRIVATE_FLAG);
- ksft_print_dbg_msg("m3:f2: %x\n", f2);
+ TH_LOG("m3:f2: %x", f2);
while (1) {
/*
@@ -125,11 +124,11 @@ TEST(futex_requeue_pi_signal_restart)
* restart futex_wait_requeue_pi() in the kernel. Wait for the
* waiter to block on f1 again.
*/
- ksft_print_dbg_msg("Issuing SIGUSR1 to waiter\n");
+ TH_LOG("Issuing SIGUSR1 to waiter");
pthread_kill(waiter, SIGUSR1);
usleep(DELAY_US);
- ksft_print_dbg_msg("Requeueing waiter via FUTEX_CMP_REQUEUE_PI\n");
+ TH_LOG("Requeueing waiter via FUTEX_CMP_REQUEUE_PI");
old_val = f1;
res = futex_cmp_requeue_pi(&f1, old_val, &(f2), 1, 0,
FUTEX_PRIVATE_FLAG);
@@ -143,10 +142,11 @@ TEST(futex_requeue_pi_signal_restart)
atomic_set(&requeued, 1);
break;
} else if (res < 0) {
- ksft_exit_fail_msg("FUTEX_CMP_REQUEUE_PI failed\n");
+ ASSERT_GE(res, 0)
+ TH_LOG("FUTEX_CMP_REQUEUE_PI failed: %s", strerror(errno));
}
}
- ksft_print_dbg_msg("m4:f2: %x\n", f2);
+ TH_LOG("m4:f2: %x", f2);
/*
* Signal the waiter after requeue, waiter should return from
@@ -154,14 +154,14 @@ TEST(futex_requeue_pi_signal_restart)
* futex_unlock_pi() can't happen before the signal wakeup is detected
* in the kernel.
*/
- ksft_print_dbg_msg("Issuing SIGUSR1 to waiter\n");
+ TH_LOG("Issuing SIGUSR1 to waiter");
pthread_kill(waiter, SIGUSR1);
- ksft_print_dbg_msg("Waiting for waiter to return\n");
+ TH_LOG("Waiting for waiter to return");
pthread_join(waiter, NULL);
- ksft_print_dbg_msg("Calling FUTEX_UNLOCK_PI on mutex=%x @ %p\n", f2, &f2);
+ TH_LOG("Calling FUTEX_UNLOCK_PI on mutex=%x @ %p", f2, &f2);
futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG);
- ksft_print_dbg_msg("m5:f2: %x\n", f2);
+ TH_LOG("m5:f2: %x", f2);
}
TEST_HARNESS_MAIN
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 5/7] selftests/futex: Migrate futex_numa_mpol to harness
2026-06-01 6:51 [PATCH 0/7] selftests/futex: Migrate requeue, NUMA and robust list tests to harness Wake Liu
` (3 preceding siblings ...)
2026-06-01 6:51 ` [PATCH 4/7] selftests/futex: Migrate futex_requeue_pi_signal_restart " Wake Liu
@ 2026-06-01 6:51 ` Wake Liu
2026-07-05 19:54 ` [tip: locking/futex] " tip-bot2 for Wake Liu
2026-06-01 6:51 ` [PATCH 6/7] selftests/futex: Migrate futex_priv_hash " Wake Liu
` (2 subsequent siblings)
7 siblings, 1 reply; 17+ messages in thread
From: Wake Liu @ 2026-06-01 6:51 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Shuah Khan, linux-kselftest
Cc: Peter Zijlstra, Darren Hart, Davidlohr Bueso, André Almeida,
Carlos Llamas, linux-kernel, wakel
Migrate futex_numa_mpol test to the kselftest harness framework,
removing mixed legacy ksft_* API usages and passing test metadata to helper functions.
Signed-off-by: Wake Liu <wakel@google.com>
---
.../futex/functional/futex_numa_mpol.c | 109 ++++++++----------
1 file changed, 51 insertions(+), 58 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/futex_numa_mpol.c b/tools/testing/selftests/futex/functional/futex_numa_mpol.c
index 78c0f7a59e17..18dc8e54aa96 100644
--- a/tools/testing/selftests/futex/functional/futex_numa_mpol.c
+++ b/tools/testing/selftests/futex/functional/futex_numa_mpol.c
@@ -10,6 +10,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <string.h>
#ifdef LIBNUMA_VER_SUFFICIENT
#include <numa.h>
#include <numaif.h>
@@ -54,7 +55,7 @@ static void *thread_lock_fn(void *arg)
return NULL;
}
-static void create_max_threads(void *futex_ptr)
+static void create_max_threads(struct __test_metadata *_metadata, void *futex_ptr)
{
int i, ret;
@@ -63,28 +64,26 @@ static void create_max_threads(void *futex_ptr)
thread_args[i].flags = FUTEX2_SIZE_U32 | FUTEX_PRIVATE_FLAG | FUTEX2_NUMA;
thread_args[i].result = 0;
ret = pthread_create(&threads[i], NULL, thread_lock_fn, &thread_args[i]);
- if (ret)
- ksft_exit_fail_msg("pthread_create failed\n");
+ ASSERT_EQ(ret, 0) TH_LOG("pthread_create failed");
}
}
-static void join_max_threads(void)
+static void join_max_threads(struct __test_metadata *_metadata)
{
int i, ret;
for (i = 0; i < MAX_THREADS; i++) {
ret = pthread_join(threads[i], NULL);
- if (ret)
- ksft_exit_fail_msg("pthread_join failed for thread %d\n", i);
+ ASSERT_EQ(ret, 0) TH_LOG("pthread_join failed for thread %d", i);
}
}
-static void __test_futex(void *futex_ptr, int err_value, unsigned int futex_flags)
+static void __test_futex(struct __test_metadata *_metadata, void *futex_ptr, int err_value, unsigned int futex_flags)
{
- int to_wake, ret, i, need_exit = 0;
+ int to_wake, ret, i;
pthread_barrier_init(&barrier_main, NULL, MAX_THREADS + 1);
- create_max_threads(futex_ptr);
+ create_max_threads(_metadata, futex_ptr);
pthread_barrier_wait(&barrier_main);
to_wake = MAX_THREADS;
@@ -92,45 +91,43 @@ static void __test_futex(void *futex_ptr, int err_value, unsigned int futex_flag
ret = futex2_wake(futex_ptr, to_wake, futex_flags);
if (err_value) {
- if (ret >= 0)
- ksft_exit_fail_msg("futex2_wake(%d, 0x%x) should fail, but didn't\n",
- to_wake, futex_flags);
+ EXPECT_LT(ret, 0)
+ TH_LOG("futex2_wake(%d, 0x%x) should fail, but didn't",
+ to_wake, futex_flags);
- if (errno != err_value)
- ksft_exit_fail_msg("futex2_wake(%d, 0x%x) expected error was %d, but returned %d (%s)\n",
- to_wake, futex_flags, err_value, errno, strerror(errno));
+ EXPECT_EQ(errno, err_value)
+ TH_LOG("futex2_wake(%d, 0x%x) expected error was %d, but returned %d (%s)",
+ to_wake, futex_flags, err_value, errno, strerror(errno));
break;
}
if (ret < 0) {
- ksft_exit_fail_msg("Failed futex2_wake(%d, 0x%x): %m\n",
- to_wake, futex_flags);
+ ASSERT_GE(ret, 0)
+ TH_LOG("Failed futex2_wake(%d, 0x%x): %s",
+ to_wake, futex_flags, strerror(errno));
}
if (!ret)
usleep(50);
to_wake -= ret;
} while (to_wake);
- join_max_threads();
+ join_max_threads(_metadata);
for (i = 0; i < MAX_THREADS; i++) {
- if (err_value && thread_args[i].result != -1) {
- ksft_print_msg("Thread %d should fail but succeeded (%d)\n",
+ if (err_value) {
+ EXPECT_EQ(thread_args[i].result, -1)
+ TH_LOG("Thread %d should fail but succeeded (%d)",
i, thread_args[i].result);
- need_exit = 1;
- }
- if (!err_value && thread_args[i].result != 0) {
- ksft_print_msg("Thread %d failed (%d)\n", i, thread_args[i].result);
- need_exit = 1;
+ } else {
+ EXPECT_EQ(thread_args[i].result, 0)
+ TH_LOG("Thread %d failed (%d)", i, thread_args[i].result);
}
}
- if (need_exit)
- ksft_exit_fail_msg("Aborting due to earlier errors.\n");
}
-static void test_futex(void *futex_ptr, int err_value)
+static void test_futex(struct __test_metadata *_metadata, void *futex_ptr, int err_value)
{
- __test_futex(futex_ptr, err_value, FUTEX2_SIZE_U32 | FUTEX_PRIVATE_FLAG | FUTEX2_NUMA);
+ __test_futex(_metadata, futex_ptr, err_value, FUTEX2_SIZE_U32 | FUTEX_PRIVATE_FLAG | FUTEX2_NUMA);
}
TEST(futex_numa_mpol)
@@ -141,43 +138,41 @@ TEST(futex_numa_mpol)
mem_size = sysconf(_SC_PAGE_SIZE);
futex_ptr = mmap(NULL, mem_size * 2, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
- if (futex_ptr == MAP_FAILED)
- ksft_exit_fail_msg("mmap() for %d bytes failed\n", mem_size);
+ ASSERT_NE(futex_ptr, MAP_FAILED)
+ TH_LOG("mmap() for %d bytes failed: %s", mem_size, strerror(errno));
/* Create an invalid memory region for the "Memory out of range" test */
mprotect(futex_ptr + mem_size, mem_size, PROT_NONE);
futex_numa = futex_ptr;
- ksft_print_msg("Regular test\n");
+ TH_LOG("Regular test");
futex_numa->futex = 0;
futex_numa->numa = FUTEX_NO_NODE;
- test_futex(futex_ptr, 0);
+ test_futex(_metadata, futex_ptr, 0);
- if (futex_numa->numa == FUTEX_NO_NODE)
- ksft_exit_fail_msg("NUMA node is left uninitialized\n");
+ EXPECT_NE(futex_numa->numa, FUTEX_NO_NODE)
+ TH_LOG("NUMA node is left uninitialized");
/* FUTEX2_NUMA futex must be 8-byte aligned */
- ksft_print_msg("Mis-aligned futex\n");
- test_futex(futex_ptr + mem_size - 4, EINVAL);
+ TH_LOG("Mis-aligned futex");
+ test_futex(_metadata, futex_ptr + mem_size - 4, EINVAL);
- ksft_print_msg("Memory out of range\n");
- test_futex(futex_ptr + mem_size, EFAULT);
+ TH_LOG("Memory out of range");
+ test_futex(_metadata, futex_ptr + mem_size, EFAULT);
futex_numa->numa = FUTEX_NO_NODE;
mprotect(futex_ptr, mem_size, PROT_READ);
- ksft_print_msg("Memory, RO\n");
- test_futex(futex_ptr, EFAULT);
+ TH_LOG("Memory, RO");
+ test_futex(_metadata, futex_ptr, EFAULT);
mprotect(futex_ptr, mem_size, PROT_NONE);
- ksft_print_msg("Memory, no access\n");
- test_futex(futex_ptr, EFAULT);
+ TH_LOG("Memory, no access");
+ test_futex(_metadata, futex_ptr, EFAULT);
mprotect(futex_ptr, mem_size, PROT_READ | PROT_WRITE);
- ksft_print_msg("Memory back to RW\n");
- test_futex(futex_ptr, 0);
-
- ksft_test_result_pass("futex2 memory boundary tests passed\n");
+ TH_LOG("Memory back to RW");
+ test_futex(_metadata, futex_ptr, 0);
/* MPOL test. Does not work as expected */
#ifdef LIBNUMA_VER_SUFFICIENT
@@ -190,25 +185,23 @@ TEST(futex_numa_mpol)
sizeof(nodemask) * 8, 0);
if (ret == 0) {
ret = numa_set_mempolicy_home_node(futex_ptr, mem_size, i, 0);
- if (ret != 0)
- ksft_exit_fail_msg("Failed to set home node: %m, %d\n", errno);
+ ASSERT_EQ(ret, 0)
+ TH_LOG("Failed to set home node: %s, %d", strerror(errno), errno);
- ksft_print_msg("Node %d test\n", i);
+ TH_LOG("Node %d test", i);
futex_numa->futex = 0;
futex_numa->numa = FUTEX_NO_NODE;
ret = futex2_wake(futex_ptr, 0, FUTEX2_SIZE_U32 | FUTEX_PRIVATE_FLAG | FUTEX2_NUMA | FUTEX2_MPOL);
- if (ret < 0)
- ksft_test_result_fail("Failed to wake 0 with MPOL: %m\n");
- if (futex_numa->numa != i) {
- ksft_exit_fail_msg("Returned NUMA node is %d expected %d\n",
- futex_numa->numa, i);
- }
+ EXPECT_GE(ret, 0)
+ TH_LOG("Failed to wake 0 with MPOL: %s", strerror(errno));
+ EXPECT_EQ(futex_numa->numa, i)
+ TH_LOG("Returned NUMA node is %d expected %d",
+ futex_numa->numa, i);
}
}
- ksft_test_result_pass("futex2 MPOL hints test passed\n");
#else
- ksft_test_result_skip("futex2 MPOL hints test requires libnuma 2.0.18+\n");
+ SKIP(return, "futex2 MPOL hints test requires libnuma 2.0.18+");
#endif
munmap(futex_ptr, mem_size * 2);
}
--
2.54.0.823.g6e5bcc1fc9-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [tip: locking/futex] selftests/futex: Migrate futex_numa_mpol to harness
2026-06-01 6:51 ` [PATCH 5/7] selftests/futex: Migrate futex_numa_mpol " Wake Liu
@ 2026-07-05 19:54 ` tip-bot2 for Wake Liu
0 siblings, 0 replies; 17+ messages in thread
From: tip-bot2 for Wake Liu @ 2026-07-05 19:54 UTC (permalink / raw)
To: linux-tip-commits; +Cc: Wake Liu, Thomas Gleixner, x86, linux-kernel
The following commit has been merged into the locking/futex branch of tip:
Commit-ID: 9b19fbb3a6c5e5fd4e7b14daa53510f6dc72d4d4
Gitweb: https://git.kernel.org/tip/9b19fbb3a6c5e5fd4e7b14daa53510f6dc72d4d4
Author: Wake Liu <wakel@google.com>
AuthorDate: Mon, 01 Jun 2026 06:51:24
Committer: Thomas Gleixner <tglx@kernel.org>
CommitterDate: Sun, 05 Jul 2026 21:49:18 +02:00
selftests/futex: Migrate futex_numa_mpol to harness
Migrate futex_numa_mpol test to the kselftest harness framework, removing
mixed legacy ksft_* API usages and passing test metadata to helper
functions.
[ tglx: Fixup coding style ]
Signed-off-by: Wake Liu <wakel@google.com>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260601065126.3623867-6-wakel@google.com
---
tools/testing/selftests/futex/functional/futex_numa_mpol.c | 124 +++----
1 file changed, 62 insertions(+), 62 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/futex_numa_mpol.c b/tools/testing/selftests/futex/functional/futex_numa_mpol.c
index 78c0f7a..c79184f 100644
--- a/tools/testing/selftests/futex/functional/futex_numa_mpol.c
+++ b/tools/testing/selftests/futex/functional/futex_numa_mpol.c
@@ -9,6 +9,7 @@
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#ifdef LIBNUMA_VER_SUFFICIENT
#include <numa.h>
@@ -28,9 +29,9 @@ static pthread_barrier_t barrier_main;
static pthread_t threads[MAX_THREADS];
struct thread_args {
- void *futex_ptr;
- unsigned int flags;
- int result;
+ void *futex_ptr;
+ unsigned int flags;
+ int result;
};
static struct thread_args thread_args[MAX_THREADS];
@@ -54,7 +55,7 @@ static void *thread_lock_fn(void *arg)
return NULL;
}
-static void create_max_threads(void *futex_ptr)
+static void create_max_threads(struct __test_metadata *_metadata, void *futex_ptr)
{
int i, ret;
@@ -63,28 +64,29 @@ static void create_max_threads(void *futex_ptr)
thread_args[i].flags = FUTEX2_SIZE_U32 | FUTEX_PRIVATE_FLAG | FUTEX2_NUMA;
thread_args[i].result = 0;
ret = pthread_create(&threads[i], NULL, thread_lock_fn, &thread_args[i]);
- if (ret)
- ksft_exit_fail_msg("pthread_create failed\n");
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_create failed");
}
}
-static void join_max_threads(void)
+static void join_max_threads(struct __test_metadata *_metadata)
{
int i, ret;
for (i = 0; i < MAX_THREADS; i++) {
ret = pthread_join(threads[i], NULL);
- if (ret)
- ksft_exit_fail_msg("pthread_join failed for thread %d\n", i);
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_join failed for thread %d", i);
}
}
-static void __test_futex(void *futex_ptr, int err_value, unsigned int futex_flags)
+static void __test_futex(struct __test_metadata *_metadata, void *futex_ptr, int err_value,
+ unsigned int futex_flags)
{
- int to_wake, ret, i, need_exit = 0;
+ int to_wake, ret, i;
pthread_barrier_init(&barrier_main, NULL, MAX_THREADS + 1);
- create_max_threads(futex_ptr);
+ create_max_threads(_metadata, futex_ptr);
pthread_barrier_wait(&barrier_main);
to_wake = MAX_THREADS;
@@ -92,45 +94,47 @@ static void __test_futex(void *futex_ptr, int err_value, unsigned int futex_flag
ret = futex2_wake(futex_ptr, to_wake, futex_flags);
if (err_value) {
- if (ret >= 0)
- ksft_exit_fail_msg("futex2_wake(%d, 0x%x) should fail, but didn't\n",
- to_wake, futex_flags);
+ EXPECT_LT(ret, 0) {
+ TH_LOG("futex2_wake(%d, 0x%x) should fail, but didn't",
+ to_wake, futex_flags);
+ }
- if (errno != err_value)
- ksft_exit_fail_msg("futex2_wake(%d, 0x%x) expected error was %d, but returned %d (%s)\n",
- to_wake, futex_flags, err_value, errno, strerror(errno));
+ EXPECT_EQ(errno, err_value) {
+ TH_LOG("futex2_wake(%d, 0x%x) expected error was %d, but returned %d (%s)",
+ to_wake, futex_flags, err_value, errno, strerror(errno));
+ }
break;
}
if (ret < 0) {
- ksft_exit_fail_msg("Failed futex2_wake(%d, 0x%x): %m\n",
- to_wake, futex_flags);
+ ASSERT_GE(ret, 0) {
+ TH_LOG("Failed futex2_wake(%d, 0x%x): %s",
+ to_wake, futex_flags, strerror(errno));
+ }
}
if (!ret)
usleep(50);
to_wake -= ret;
} while (to_wake);
- join_max_threads();
+ join_max_threads(_metadata);
for (i = 0; i < MAX_THREADS; i++) {
- if (err_value && thread_args[i].result != -1) {
- ksft_print_msg("Thread %d should fail but succeeded (%d)\n",
+ if (err_value) {
+ EXPECT_EQ(thread_args[i].result, -1) {
+ TH_LOG("Thread %d should fail but succeeded (%d)",
i, thread_args[i].result);
- need_exit = 1;
- }
- if (!err_value && thread_args[i].result != 0) {
- ksft_print_msg("Thread %d failed (%d)\n", i, thread_args[i].result);
- need_exit = 1;
+ }
+ } else {
+ EXPECT_EQ(thread_args[i].result, 0)
+ TH_LOG("Thread %d failed (%d)", i, thread_args[i].result);
}
}
- if (need_exit)
- ksft_exit_fail_msg("Aborting due to earlier errors.\n");
}
-static void test_futex(void *futex_ptr, int err_value)
+static void test_futex(struct __test_metadata *_metadata, void *futex_ptr, int err_value)
{
- __test_futex(futex_ptr, err_value, FUTEX2_SIZE_U32 | FUTEX_PRIVATE_FLAG | FUTEX2_NUMA);
+ __test_futex(_metadata, futex_ptr, err_value, FUTEX2_SIZE_U32 | FUTEX_PRIVATE_FLAG | FUTEX2_NUMA);
}
TEST(futex_numa_mpol)
@@ -141,43 +145,41 @@ TEST(futex_numa_mpol)
mem_size = sysconf(_SC_PAGE_SIZE);
futex_ptr = mmap(NULL, mem_size * 2, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
- if (futex_ptr == MAP_FAILED)
- ksft_exit_fail_msg("mmap() for %d bytes failed\n", mem_size);
+ ASSERT_NE(futex_ptr, MAP_FAILED)
+ TH_LOG("mmap() for %d bytes failed: %s", mem_size, strerror(errno));
/* Create an invalid memory region for the "Memory out of range" test */
mprotect(futex_ptr + mem_size, mem_size, PROT_NONE);
futex_numa = futex_ptr;
- ksft_print_msg("Regular test\n");
+ TH_LOG("Regular test");
futex_numa->futex = 0;
futex_numa->numa = FUTEX_NO_NODE;
- test_futex(futex_ptr, 0);
+ test_futex(_metadata, futex_ptr, 0);
- if (futex_numa->numa == FUTEX_NO_NODE)
- ksft_exit_fail_msg("NUMA node is left uninitialized\n");
+ EXPECT_NE(futex_numa->numa, FUTEX_NO_NODE)
+ TH_LOG("NUMA node is left uninitialized");
/* FUTEX2_NUMA futex must be 8-byte aligned */
- ksft_print_msg("Mis-aligned futex\n");
- test_futex(futex_ptr + mem_size - 4, EINVAL);
+ TH_LOG("Mis-aligned futex");
+ test_futex(_metadata, futex_ptr + mem_size - 4, EINVAL);
- ksft_print_msg("Memory out of range\n");
- test_futex(futex_ptr + mem_size, EFAULT);
+ TH_LOG("Memory out of range");
+ test_futex(_metadata, futex_ptr + mem_size, EFAULT);
futex_numa->numa = FUTEX_NO_NODE;
mprotect(futex_ptr, mem_size, PROT_READ);
- ksft_print_msg("Memory, RO\n");
- test_futex(futex_ptr, EFAULT);
+ TH_LOG("Memory, RO");
+ test_futex(_metadata, futex_ptr, EFAULT);
mprotect(futex_ptr, mem_size, PROT_NONE);
- ksft_print_msg("Memory, no access\n");
- test_futex(futex_ptr, EFAULT);
+ TH_LOG("Memory, no access");
+ test_futex(_metadata, futex_ptr, EFAULT);
mprotect(futex_ptr, mem_size, PROT_READ | PROT_WRITE);
- ksft_print_msg("Memory back to RW\n");
- test_futex(futex_ptr, 0);
-
- ksft_test_result_pass("futex2 memory boundary tests passed\n");
+ TH_LOG("Memory back to RW");
+ test_futex(_metadata, futex_ptr, 0);
/* MPOL test. Does not work as expected */
#ifdef LIBNUMA_VER_SUFFICIENT
@@ -190,25 +192,23 @@ TEST(futex_numa_mpol)
sizeof(nodemask) * 8, 0);
if (ret == 0) {
ret = numa_set_mempolicy_home_node(futex_ptr, mem_size, i, 0);
- if (ret != 0)
- ksft_exit_fail_msg("Failed to set home node: %m, %d\n", errno);
+ ASSERT_EQ(ret, 0)
+ TH_LOG("Failed to set home node: %s, %d", strerror(errno), errno);
- ksft_print_msg("Node %d test\n", i);
+ TH_LOG("Node %d test", i);
futex_numa->futex = 0;
futex_numa->numa = FUTEX_NO_NODE;
- ret = futex2_wake(futex_ptr, 0, FUTEX2_SIZE_U32 | FUTEX_PRIVATE_FLAG | FUTEX2_NUMA | FUTEX2_MPOL);
- if (ret < 0)
- ksft_test_result_fail("Failed to wake 0 with MPOL: %m\n");
- if (futex_numa->numa != i) {
- ksft_exit_fail_msg("Returned NUMA node is %d expected %d\n",
- futex_numa->numa, i);
- }
+ ret = futex2_wake(futex_ptr, 0, FUTEX2_SIZE_U32 | FUTEX_PRIVATE_FLAG |
+ FUTEX2_NUMA | FUTEX2_MPOL);
+ EXPECT_GE(ret, 0)
+ TH_LOG("Failed to wake 0 with MPOL: %s", strerror(errno));
+ EXPECT_EQ(futex_numa->numa, i)
+ TH_LOG("Returned NUMA node is %d expected %d", futex_numa->numa, i);
}
}
- ksft_test_result_pass("futex2 MPOL hints test passed\n");
#else
- ksft_test_result_skip("futex2 MPOL hints test requires libnuma 2.0.18+\n");
+ SKIP(return, "futex2 MPOL hints test requires libnuma 2.0.18+");
#endif
munmap(futex_ptr, mem_size * 2);
}
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 6/7] selftests/futex: Migrate futex_priv_hash to harness
2026-06-01 6:51 [PATCH 0/7] selftests/futex: Migrate requeue, NUMA and robust list tests to harness Wake Liu
` (4 preceding siblings ...)
2026-06-01 6:51 ` [PATCH 5/7] selftests/futex: Migrate futex_numa_mpol " Wake Liu
@ 2026-06-01 6:51 ` Wake Liu
2026-07-05 19:54 ` [tip: locking/futex] " tip-bot2 for Wake Liu
2026-06-01 6:51 ` [PATCH 7/7] selftests/futex: Migrate robust_list " Wake Liu
2026-06-01 8:24 ` [PATCH 0/7] selftests/futex: Migrate requeue, NUMA and robust list tests " Peter Zijlstra
7 siblings, 1 reply; 17+ messages in thread
From: Wake Liu @ 2026-06-01 6:51 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Shuah Khan, linux-kselftest
Cc: Peter Zijlstra, Darren Hart, Davidlohr Bueso, André Almeida,
Carlos Llamas, linux-kernel, wakel
Migrate futex_priv_hash test to the kselftest harness framework,
removing mixed legacy ksft_* API usages and passing test metadata
to all helper functions.
Signed-off-by: Wake Liu <wakel@google.com>
---
.../futex/functional/futex_priv_hash.c | 160 +++++++++---------
1 file changed, 78 insertions(+), 82 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/futex_priv_hash.c b/tools/testing/selftests/futex/functional/futex_priv_hash.c
index e8079d7c65e8..60d500598f2b 100644
--- a/tools/testing/selftests/futex/functional/futex_priv_hash.c
+++ b/tools/testing/selftests/futex/functional/futex_priv_hash.c
@@ -10,6 +10,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <string.h>
#include <linux/prctl.h>
#include <sys/prctl.h>
@@ -39,31 +40,27 @@ static int futex_hash_slots_get(void)
return prctl(PR_FUTEX_HASH, PR_FUTEX_HASH_GET_SLOTS);
}
-static void futex_hash_slots_set_verify(int slots)
+static void futex_hash_slots_set_verify(struct __test_metadata *_metadata, int slots)
{
int ret;
ret = futex_hash_slots_set(slots);
- if (ret != 0) {
- ksft_test_result_fail("Failed to set slots to %d: %m\n", slots);
- ksft_finished();
- }
+ ASSERT_EQ(ret, 0)
+ TH_LOG("Failed to set slots to %d: %s", slots, strerror(errno));
+
ret = futex_hash_slots_get();
- if (ret != slots) {
- ksft_test_result_fail("Set %d slots but PR_FUTEX_HASH_GET_SLOTS returns: %d, %m\n",
- slots, ret);
- ksft_finished();
- }
- ksft_test_result_pass("SET and GET slots %d passed\n", slots);
+ ASSERT_EQ(ret, slots)
+ TH_LOG("Set %d slots but PR_FUTEX_HASH_GET_SLOTS returns: %d, %s",
+ slots, ret, strerror(errno));
}
-static void futex_hash_slots_set_must_fail(int slots)
+static void futex_hash_slots_set_must_fail(struct __test_metadata *_metadata, int slots)
{
int ret;
ret = futex_hash_slots_set(slots);
- ksft_test_result(ret < 0, "futex_hash_slots_set(%d)\n",
- slots);
+ EXPECT_LT(ret, 0)
+ TH_LOG("futex_hash_slots_set(%d) should fail but succeeded", slots);
}
static void *thread_return_fn(void *arg)
@@ -82,32 +79,32 @@ static void *thread_lock_fn(void *arg)
return NULL;
}
-static void create_max_threads(void *(*thread_fn)(void *))
+static void create_max_threads(struct __test_metadata *_metadata, void *(*thread_fn)(void *))
{
int i, ret;
for (i = 0; i < MAX_THREADS; i++) {
ret = pthread_create(&threads[i], NULL, thread_fn, NULL);
- if (ret)
- ksft_exit_fail_msg("pthread_create failed: %m\n");
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_create failed: %s", strerror(errno));
}
}
-static void join_max_threads(void)
+static void join_max_threads(struct __test_metadata *_metadata)
{
int i, ret;
for (i = 0; i < MAX_THREADS; i++) {
ret = pthread_join(threads[i], NULL);
- if (ret)
- ksft_exit_fail_msg("pthread_join failed for thread %d\n", i);
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_join failed for thread %d: %s", i, strerror(errno));
}
}
#define SEC_IN_NSEC 1000000000
#define MSEC_IN_NSEC 1000000
-static void futex_dummy_op(void)
+static void futex_dummy_op(struct __test_metadata *_metadata)
{
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
struct timespec timeout;
@@ -121,11 +118,11 @@ static void futex_dummy_op(void)
timeout.tv_sec++;
}
ret = pthread_mutex_timedlock(&lock, &timeout);
- if (ret == 0)
- ksft_exit_fail_msg("Successfully locked an already locked mutex.\n");
+ ASSERT_NE(ret, 0)
+ TH_LOG("Successfully locked an already locked mutex");
- if (ret != ETIMEDOUT)
- ksft_exit_fail_msg("pthread_mutex_timedlock() did not timeout: %d.\n", ret);
+ ASSERT_EQ(ret, ETIMEDOUT)
+ TH_LOG("pthread_mutex_timedlock() did not timeout: %d", ret);
}
static const char *test_msg_auto_create = "Automatic hash bucket init on thread creation.\n";
@@ -140,50 +137,45 @@ TEST(priv_hash)
ret = pthread_mutexattr_init(&mutex_attr_pi);
ret |= pthread_mutexattr_setprotocol(&mutex_attr_pi, PTHREAD_PRIO_INHERIT);
ret |= pthread_mutex_init(&global_lock, &mutex_attr_pi);
- if (ret != 0) {
- ksft_exit_fail_msg("Failed to initialize pthread mutex.\n");
- }
+ ASSERT_EQ(ret, 0)
+ TH_LOG("Failed to initialize pthread mutex");
+
/* First thread, expect to be 0, not yet initialized */
ret = futex_hash_slots_get();
- if (ret != 0)
- ksft_exit_fail_msg("futex_hash_slots_get() failed: %d, %m\n", ret);
+ ASSERT_EQ(ret, 0)
+ TH_LOG("futex_hash_slots_get() failed: %d, %s", ret, strerror(errno));
- ksft_test_result_pass("Basic get slots and immutable status.\n");
ret = pthread_create(&threads[0], NULL, thread_return_fn, NULL);
- if (ret != 0)
- ksft_exit_fail_msg("pthread_create() failed: %d, %m\n", ret);
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_create() failed: %d, %s", ret, strerror(errno));
ret = pthread_join(threads[0], NULL);
- if (ret != 0)
- ksft_exit_fail_msg("pthread_join() failed: %d, %m\n", ret);
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_join() failed: %d, %s", ret, strerror(errno));
/* First thread, has to initialize private hash */
futex_slots1 = futex_hash_slots_get();
- if (futex_slots1 <= 0) {
- ksft_print_msg("Current hash buckets: %d\n", futex_slots1);
- ksft_exit_fail_msg("%s", test_msg_auto_create);
- }
-
- ksft_test_result_pass("%s", test_msg_auto_create);
+ EXPECT_GT(futex_slots1, 0)
+ TH_LOG("Current hash buckets: %d. %s", futex_slots1, test_msg_auto_create);
online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
ret = pthread_barrier_init(&barrier_main, NULL, MAX_THREADS + 1);
- if (ret != 0)
- ksft_exit_fail_msg("pthread_barrier_init failed: %m.\n");
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_barrier_init failed: %s", strerror(errno));
ret = pthread_mutex_lock(&global_lock);
- if (ret != 0)
- ksft_exit_fail_msg("pthread_mutex_lock failed: %m.\n");
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_mutex_lock failed: %s", strerror(errno));
counter = 0;
- create_max_threads(thread_lock_fn);
+ create_max_threads(_metadata, thread_lock_fn);
pthread_barrier_wait(&barrier_main);
/*
* The current default size of hash buckets is 16. The auto increase
* works only if more than 16 CPUs are available.
*/
- ksft_print_msg("Online CPUs: %d\n", online_cpus);
+ TH_LOG("Online CPUs: %d", online_cpus);
if (online_cpus > 16) {
retry_getslots:
futex_slotsn = futex_hash_slots_get();
@@ -200,71 +192,75 @@ TEST(priv_hash)
* sleep for 100ms and issue a futex operation.
*/
if (retry > 0) {
- futex_dummy_op();
+ futex_dummy_op(_metadata);
goto retry_getslots;
}
- ksft_print_msg("Expected increase of hash buckets but got: %d -> %d\n",
- futex_slots1, futex_slotsn);
- ksft_exit_fail_msg("%s", test_msg_auto_inc);
+ EXPECT_NE(futex_slots1, futex_slotsn)
+ TH_LOG("Expected increase of hash buckets but got: %d -> %d. %s",
+ futex_slots1, futex_slotsn, test_msg_auto_inc);
}
- ksft_test_result_pass("%s", test_msg_auto_inc);
} else {
- ksft_test_result_skip("%s", test_msg_auto_inc);
+ SKIP(return, "Automatic increase with more than 16 CPUs (only %d online)", online_cpus);
}
ret = pthread_mutex_unlock(&global_lock);
/* Once the user changes it, it has to be what is set */
- futex_hash_slots_set_verify(2);
- futex_hash_slots_set_verify(4);
- futex_hash_slots_set_verify(8);
- futex_hash_slots_set_verify(32);
- futex_hash_slots_set_verify(16);
+ futex_hash_slots_set_verify(_metadata, 2);
+ futex_hash_slots_set_verify(_metadata, 4);
+ futex_hash_slots_set_verify(_metadata, 8);
+ futex_hash_slots_set_verify(_metadata, 32);
+ futex_hash_slots_set_verify(_metadata, 16);
ret = futex_hash_slots_set(15);
- ksft_test_result(ret < 0, "Use 15 slots\n");
+ EXPECT_LT(ret, 0)
+ TH_LOG("Use 15 slots should fail but succeeded");
+
+ futex_hash_slots_set_verify(_metadata, 2);
+ join_max_threads(_metadata);
+
+ EXPECT_EQ(counter, MAX_THREADS)
+ TH_LOG("Created and waited for %d of %d threads", counter, MAX_THREADS);
- futex_hash_slots_set_verify(2);
- join_max_threads();
- ksft_test_result(counter == MAX_THREADS, "Created and waited for %d of %d threads\n",
- counter, MAX_THREADS);
counter = 0;
/* Once the user set something, auto resize must be disabled */
ret = pthread_barrier_init(&barrier_main, NULL, MAX_THREADS);
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_barrier_init failed: %s", strerror(errno));
- create_max_threads(thread_lock_fn);
- join_max_threads();
+ create_max_threads(_metadata, thread_lock_fn);
+ join_max_threads(_metadata);
ret = futex_hash_slots_get();
- ksft_test_result(ret == 2, "No more auto-resize after manual setting, got %d\n",
- ret);
+ EXPECT_EQ(ret, 2)
+ TH_LOG("No more auto-resize after manual setting, got %d", ret);
- futex_hash_slots_set_must_fail(1 << 29);
- futex_hash_slots_set_verify(4);
+ futex_hash_slots_set_must_fail(_metadata, 1 << 29);
+ futex_hash_slots_set_verify(_metadata, 4);
/*
* Once the global hash has been requested, then this requested can not
* be undone.
*/
ret = futex_hash_slots_set(0);
- ksft_test_result(ret == 0, "Global hash request\n");
- if (ret != 0)
- return;
+ ASSERT_EQ(ret, 0)
+ TH_LOG("Global hash request failed: %s", strerror(errno));
- futex_hash_slots_set_must_fail(4);
- futex_hash_slots_set_must_fail(8);
- futex_hash_slots_set_must_fail(8);
- futex_hash_slots_set_must_fail(0);
- futex_hash_slots_set_must_fail(6);
+ futex_hash_slots_set_must_fail(_metadata, 4);
+ futex_hash_slots_set_must_fail(_metadata, 8);
+ futex_hash_slots_set_must_fail(_metadata, 8);
+ futex_hash_slots_set_must_fail(_metadata, 0);
+ futex_hash_slots_set_must_fail(_metadata, 6);
ret = pthread_barrier_init(&barrier_main, NULL, MAX_THREADS);
- if (ret != 0)
- ksft_exit_fail_msg("pthread_barrier_init failed: %m\n");
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_barrier_init failed: %s", strerror(errno));
- create_max_threads(thread_lock_fn);
- join_max_threads();
+ create_max_threads(_metadata, thread_lock_fn);
+ join_max_threads(_metadata);
ret = futex_hash_slots_get();
- ksft_test_result(ret == 0, "Continue to use global hash\n");
+ EXPECT_EQ(ret, 0)
+ TH_LOG("Continue to use global hash failed");
}
TEST_HARNESS_MAIN
--
2.54.0.823.g6e5bcc1fc9-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [tip: locking/futex] selftests/futex: Migrate futex_priv_hash to harness
2026-06-01 6:51 ` [PATCH 6/7] selftests/futex: Migrate futex_priv_hash " Wake Liu
@ 2026-07-05 19:54 ` tip-bot2 for Wake Liu
0 siblings, 0 replies; 17+ messages in thread
From: tip-bot2 for Wake Liu @ 2026-07-05 19:54 UTC (permalink / raw)
To: linux-tip-commits; +Cc: Wake Liu, Thomas Gleixner, x86, linux-kernel
The following commit has been merged into the locking/futex branch of tip:
Commit-ID: 4f22ba7eee3e1ed67095edd49fb99db4032343ab
Gitweb: https://git.kernel.org/tip/4f22ba7eee3e1ed67095edd49fb99db4032343ab
Author: Wake Liu <wakel@google.com>
AuthorDate: Mon, 01 Jun 2026 06:51:25
Committer: Thomas Gleixner <tglx@kernel.org>
CommitterDate: Sun, 05 Jul 2026 21:49:18 +02:00
selftests/futex: Migrate futex_priv_hash to harness
Migrate futex_priv_hash test to the kselftest harness framework, removing
mixed legacy ksft_* API usages and passing test metadata to all helper
functions.
[ tglx: Fixup coding style ]
Signed-off-by: Wake Liu <wakel@google.com>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260601065126.3623867-7-wakel@google.com
---
tools/testing/selftests/futex/functional/futex_priv_hash.c | 160 +++----
1 file changed, 79 insertions(+), 81 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/futex_priv_hash.c b/tools/testing/selftests/futex/functional/futex_priv_hash.c
index e8079d7..a742a79 100644
--- a/tools/testing/selftests/futex/functional/futex_priv_hash.c
+++ b/tools/testing/selftests/futex/functional/futex_priv_hash.c
@@ -9,6 +9,7 @@
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include <linux/prctl.h>
@@ -39,31 +40,28 @@ static int futex_hash_slots_get(void)
return prctl(PR_FUTEX_HASH, PR_FUTEX_HASH_GET_SLOTS);
}
-static void futex_hash_slots_set_verify(int slots)
+static void futex_hash_slots_set_verify(struct __test_metadata *_metadata, int slots)
{
int ret;
ret = futex_hash_slots_set(slots);
- if (ret != 0) {
- ksft_test_result_fail("Failed to set slots to %d: %m\n", slots);
- ksft_finished();
- }
+ ASSERT_EQ(ret, 0)
+ TH_LOG("Failed to set slots to %d: %s", slots, strerror(errno));
+
ret = futex_hash_slots_get();
- if (ret != slots) {
- ksft_test_result_fail("Set %d slots but PR_FUTEX_HASH_GET_SLOTS returns: %d, %m\n",
- slots, ret);
- ksft_finished();
+ ASSERT_EQ(ret, slots) {
+ TH_LOG("Set %d slots but PR_FUTEX_HASH_GET_SLOTS returns: %d, %s",
+ slots, ret, strerror(errno));
}
- ksft_test_result_pass("SET and GET slots %d passed\n", slots);
}
-static void futex_hash_slots_set_must_fail(int slots)
+static void futex_hash_slots_set_must_fail(struct __test_metadata *_metadata, int slots)
{
int ret;
ret = futex_hash_slots_set(slots);
- ksft_test_result(ret < 0, "futex_hash_slots_set(%d)\n",
- slots);
+ EXPECT_LT(ret, 0)
+ TH_LOG("futex_hash_slots_set(%d) should fail but succeeded", slots);
}
static void *thread_return_fn(void *arg)
@@ -82,32 +80,32 @@ static void *thread_lock_fn(void *arg)
return NULL;
}
-static void create_max_threads(void *(*thread_fn)(void *))
+static void create_max_threads(struct __test_metadata *_metadata, void *(*thread_fn)(void *))
{
int i, ret;
for (i = 0; i < MAX_THREADS; i++) {
ret = pthread_create(&threads[i], NULL, thread_fn, NULL);
- if (ret)
- ksft_exit_fail_msg("pthread_create failed: %m\n");
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_create failed: %s", strerror(errno));
}
}
-static void join_max_threads(void)
+static void join_max_threads(struct __test_metadata *_metadata)
{
int i, ret;
for (i = 0; i < MAX_THREADS; i++) {
ret = pthread_join(threads[i], NULL);
- if (ret)
- ksft_exit_fail_msg("pthread_join failed for thread %d\n", i);
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_join failed for thread %d: %s", i, strerror(errno));
}
}
#define SEC_IN_NSEC 1000000000
#define MSEC_IN_NSEC 1000000
-static void futex_dummy_op(void)
+static void futex_dummy_op(struct __test_metadata *_metadata)
{
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
struct timespec timeout;
@@ -121,11 +119,11 @@ static void futex_dummy_op(void)
timeout.tv_sec++;
}
ret = pthread_mutex_timedlock(&lock, &timeout);
- if (ret == 0)
- ksft_exit_fail_msg("Successfully locked an already locked mutex.\n");
+ ASSERT_NE(ret, 0)
+ TH_LOG("Successfully locked an already locked mutex");
- if (ret != ETIMEDOUT)
- ksft_exit_fail_msg("pthread_mutex_timedlock() did not timeout: %d.\n", ret);
+ ASSERT_EQ(ret, ETIMEDOUT)
+ TH_LOG("pthread_mutex_timedlock() did not timeout: %d", ret);
}
static const char *test_msg_auto_create = "Automatic hash bucket init on thread creation.\n";
@@ -140,50 +138,45 @@ TEST(priv_hash)
ret = pthread_mutexattr_init(&mutex_attr_pi);
ret |= pthread_mutexattr_setprotocol(&mutex_attr_pi, PTHREAD_PRIO_INHERIT);
ret |= pthread_mutex_init(&global_lock, &mutex_attr_pi);
- if (ret != 0) {
- ksft_exit_fail_msg("Failed to initialize pthread mutex.\n");
- }
+ ASSERT_EQ(ret, 0)
+ TH_LOG("Failed to initialize pthread mutex");
+
/* First thread, expect to be 0, not yet initialized */
ret = futex_hash_slots_get();
- if (ret != 0)
- ksft_exit_fail_msg("futex_hash_slots_get() failed: %d, %m\n", ret);
+ ASSERT_EQ(ret, 0)
+ TH_LOG("futex_hash_slots_get() failed: %d, %s", ret, strerror(errno));
- ksft_test_result_pass("Basic get slots and immutable status.\n");
ret = pthread_create(&threads[0], NULL, thread_return_fn, NULL);
- if (ret != 0)
- ksft_exit_fail_msg("pthread_create() failed: %d, %m\n", ret);
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_create() failed: %d, %s", ret, strerror(errno));
ret = pthread_join(threads[0], NULL);
- if (ret != 0)
- ksft_exit_fail_msg("pthread_join() failed: %d, %m\n", ret);
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_join() failed: %d, %s", ret, strerror(errno));
/* First thread, has to initialize private hash */
futex_slots1 = futex_hash_slots_get();
- if (futex_slots1 <= 0) {
- ksft_print_msg("Current hash buckets: %d\n", futex_slots1);
- ksft_exit_fail_msg("%s", test_msg_auto_create);
- }
-
- ksft_test_result_pass("%s", test_msg_auto_create);
+ EXPECT_GT(futex_slots1, 0)
+ TH_LOG("Current hash buckets: %d. %s", futex_slots1, test_msg_auto_create);
online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
ret = pthread_barrier_init(&barrier_main, NULL, MAX_THREADS + 1);
- if (ret != 0)
- ksft_exit_fail_msg("pthread_barrier_init failed: %m.\n");
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_barrier_init failed: %s", strerror(errno));
ret = pthread_mutex_lock(&global_lock);
- if (ret != 0)
- ksft_exit_fail_msg("pthread_mutex_lock failed: %m.\n");
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_mutex_lock failed: %s", strerror(errno));
counter = 0;
- create_max_threads(thread_lock_fn);
+ create_max_threads(_metadata, thread_lock_fn);
pthread_barrier_wait(&barrier_main);
/*
* The current default size of hash buckets is 16. The auto increase
* works only if more than 16 CPUs are available.
*/
- ksft_print_msg("Online CPUs: %d\n", online_cpus);
+ TH_LOG("Online CPUs: %d", online_cpus);
if (online_cpus > 16) {
retry_getslots:
futex_slotsn = futex_hash_slots_get();
@@ -200,71 +193,76 @@ retry_getslots:
* sleep for 100ms and issue a futex operation.
*/
if (retry > 0) {
- futex_dummy_op();
+ futex_dummy_op(_metadata);
goto retry_getslots;
}
- ksft_print_msg("Expected increase of hash buckets but got: %d -> %d\n",
- futex_slots1, futex_slotsn);
- ksft_exit_fail_msg("%s", test_msg_auto_inc);
+ EXPECT_NE(futex_slots1, futex_slotsn) {
+ TH_LOG("Expected increase of hash buckets but got: %d -> %d. %s",
+ futex_slots1, futex_slotsn, test_msg_auto_inc);
+ }
}
- ksft_test_result_pass("%s", test_msg_auto_inc);
} else {
- ksft_test_result_skip("%s", test_msg_auto_inc);
+ SKIP(return, "Automatic increase with more than 16 CPUs (only %d online)", online_cpus);
}
ret = pthread_mutex_unlock(&global_lock);
/* Once the user changes it, it has to be what is set */
- futex_hash_slots_set_verify(2);
- futex_hash_slots_set_verify(4);
- futex_hash_slots_set_verify(8);
- futex_hash_slots_set_verify(32);
- futex_hash_slots_set_verify(16);
+ futex_hash_slots_set_verify(_metadata, 2);
+ futex_hash_slots_set_verify(_metadata, 4);
+ futex_hash_slots_set_verify(_metadata, 8);
+ futex_hash_slots_set_verify(_metadata, 32);
+ futex_hash_slots_set_verify(_metadata, 16);
ret = futex_hash_slots_set(15);
- ksft_test_result(ret < 0, "Use 15 slots\n");
+ EXPECT_LT(ret, 0)
+ TH_LOG("Use 15 slots should fail but succeeded");
+
+ futex_hash_slots_set_verify(_metadata, 2);
+ join_max_threads(_metadata);
+
+ EXPECT_EQ(counter, MAX_THREADS)
+ TH_LOG("Created and waited for %d of %d threads", counter, MAX_THREADS);
- futex_hash_slots_set_verify(2);
- join_max_threads();
- ksft_test_result(counter == MAX_THREADS, "Created and waited for %d of %d threads\n",
- counter, MAX_THREADS);
counter = 0;
/* Once the user set something, auto resize must be disabled */
ret = pthread_barrier_init(&barrier_main, NULL, MAX_THREADS);
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_barrier_init failed: %s", strerror(errno));
- create_max_threads(thread_lock_fn);
- join_max_threads();
+ create_max_threads(_metadata, thread_lock_fn);
+ join_max_threads(_metadata);
ret = futex_hash_slots_get();
- ksft_test_result(ret == 2, "No more auto-resize after manual setting, got %d\n",
- ret);
+ EXPECT_EQ(ret, 2)
+ TH_LOG("No more auto-resize after manual setting, got %d", ret);
- futex_hash_slots_set_must_fail(1 << 29);
- futex_hash_slots_set_verify(4);
+ futex_hash_slots_set_must_fail(_metadata, 1 << 29);
+ futex_hash_slots_set_verify(_metadata, 4);
/*
* Once the global hash has been requested, then this requested can not
* be undone.
*/
ret = futex_hash_slots_set(0);
- ksft_test_result(ret == 0, "Global hash request\n");
- if (ret != 0)
- return;
+ ASSERT_EQ(ret, 0)
+ TH_LOG("Global hash request failed: %s", strerror(errno));
- futex_hash_slots_set_must_fail(4);
- futex_hash_slots_set_must_fail(8);
- futex_hash_slots_set_must_fail(8);
- futex_hash_slots_set_must_fail(0);
- futex_hash_slots_set_must_fail(6);
+ futex_hash_slots_set_must_fail(_metadata, 4);
+ futex_hash_slots_set_must_fail(_metadata, 8);
+ futex_hash_slots_set_must_fail(_metadata, 8);
+ futex_hash_slots_set_must_fail(_metadata, 0);
+ futex_hash_slots_set_must_fail(_metadata, 6);
ret = pthread_barrier_init(&barrier_main, NULL, MAX_THREADS);
- if (ret != 0)
- ksft_exit_fail_msg("pthread_barrier_init failed: %m\n");
+ ASSERT_EQ(ret, 0)
+ TH_LOG("pthread_barrier_init failed: %s", strerror(errno));
- create_max_threads(thread_lock_fn);
- join_max_threads();
+ create_max_threads(_metadata, thread_lock_fn);
+ join_max_threads(_metadata);
ret = futex_hash_slots_get();
- ksft_test_result(ret == 0, "Continue to use global hash\n");
+ EXPECT_EQ(ret, 0)
+ TH_LOG("Continue to use global hash failed");
}
TEST_HARNESS_MAIN
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 7/7] selftests/futex: Migrate robust_list to harness
2026-06-01 6:51 [PATCH 0/7] selftests/futex: Migrate requeue, NUMA and robust list tests to harness Wake Liu
` (5 preceding siblings ...)
2026-06-01 6:51 ` [PATCH 6/7] selftests/futex: Migrate futex_priv_hash " Wake Liu
@ 2026-06-01 6:51 ` Wake Liu
2026-07-05 19:54 ` [tip: locking/futex] " tip-bot2 for Wake Liu
2026-06-01 8:24 ` [PATCH 0/7] selftests/futex: Migrate requeue, NUMA and robust list tests " Peter Zijlstra
7 siblings, 1 reply; 17+ messages in thread
From: Wake Liu @ 2026-06-01 6:51 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Shuah Khan, linux-kselftest
Cc: Peter Zijlstra, Darren Hart, Davidlohr Bueso, André Almeida,
Carlos Llamas, linux-kernel, wakel
Migrate robust_list test to the kselftest harness framework,
removing mixed legacy ksft_* API usages and passing test metadata
to cloned child functions via child_args struct.
Also, fix an out-of-bounds waitpid bug during multithreaded tests.
Signed-off-by: Wake Liu <wakel@google.com>
---
.../selftests/futex/functional/robust_list.c | 166 +++++++++---------
1 file changed, 85 insertions(+), 81 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/robust_list.c b/tools/testing/selftests/futex/functional/robust_list.c
index e7d1254e18ca..d0b461962586 100644
--- a/tools/testing/selftests/futex/functional/robust_list.c
+++ b/tools/testing/selftests/futex/functional/robust_list.c
@@ -25,7 +25,7 @@
#define _GNU_SOURCE
#include "futextest.h"
-#include "../../kselftest_harness.h"
+#include "kselftest_harness.h"
#include <errno.h>
#include <pthread.h>
@@ -35,11 +35,11 @@
#include <stddef.h>
#include <sys/mman.h>
#include <sys/wait.h>
+#include <stdlib.h>
+#include <string.h>
#define STACK_SIZE (1024 * 1024)
-
#define FUTEX_TIMEOUT 3
-
#define SLEEP_US 100
static pthread_barrier_t barrier, barrier2;
@@ -58,30 +58,46 @@ static int get_robust_list(int pid, struct robust_list_head **head, size_t *len_
* Basic lock struct, contains just the futex word and the robust list element
* Real implementations have also a *prev to easily walk in the list
*/
+typedef _Atomic(unsigned int) atomic_futex_t;
+
struct lock_struct {
- _Atomic(unsigned int) futex;
+ atomic_futex_t futex;
struct robust_list list;
};
+struct child_args {
+ struct __test_metadata *_metadata;
+ void *arg;
+};
+
/*
* Helper function to spawn a child thread. Returns -1 on error, pid on success
*/
-static int create_child(int (*fn)(void *arg), void *arg)
+static int create_child(struct __test_metadata *_metadata, int (*fn)(void *arg), void *arg)
{
char *stack;
pid_t pid;
+ struct child_args *cargs = malloc(sizeof(*cargs));
+
+ if (!cargs)
+ return -1;
+ cargs->_metadata = _metadata;
+ cargs->arg = arg;
stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
- if (stack == MAP_FAILED)
+ if (stack == MAP_FAILED) {
+ free(cargs);
return -1;
+ }
stack += STACK_SIZE;
- pid = clone(fn, stack, CLONE_VM | SIGCHLD, arg);
-
- if (pid == -1)
+ pid = clone(fn, stack, CLONE_VM | SIGCHLD, cargs);
+ if (pid == -1) {
+ free(cargs);
return -1;
+ }
return pid;
}
@@ -110,7 +126,7 @@ static int set_list(struct robust_list_head *head)
*/
static int mutex_lock(struct lock_struct *lock, struct robust_list_head *head, bool error_inject)
{
- _Atomic(unsigned int) *futex = &lock->futex;
+ atomic_futex_t *futex = &lock->futex;
unsigned int zero = 0;
pid_t tid = gettid();
int ret = -1;
@@ -170,21 +186,19 @@ static int mutex_lock(struct lock_struct *lock, struct robust_list_head *head, b
*/
static int child_fn_lock(void *arg)
{
- struct lock_struct *lock = arg;
+ struct child_args *cargs = arg;
+ struct __test_metadata *_metadata = cargs->_metadata;
+ struct lock_struct *lock = cargs->arg;
struct robust_list_head head;
int ret;
+ free(cargs);
+
ret = set_list(&head);
- if (ret) {
- ksft_test_result_fail("set_robust_list error\n");
- return ret;
- }
+ ASSERT_EQ(ret, 0) TH_LOG("set_robust_list error");
ret = mutex_lock(lock, &head, false);
- if (ret) {
- ksft_test_result_fail("mutex_lock error\n");
- return ret;
- }
+ ASSERT_EQ(ret, 0) TH_LOG("mutex_lock error");
pthread_barrier_wait(&barrier);
@@ -207,7 +221,7 @@ static int child_fn_lock(void *arg)
TEST(test_robustness)
{
struct lock_struct lock = { .futex = 0 };
- _Atomic(unsigned int) *futex = &lock.futex;
+ atomic_futex_t *futex = &lock.futex;
struct robust_list_head head;
int ret, pid, wstatus;
@@ -221,7 +235,7 @@ TEST(test_robustness)
ret = pthread_barrier_init(&barrier, NULL, 2);
ASSERT_EQ(ret, 0);
- pid = create_child(&child_fn_lock, &lock);
+ pid = create_child(_metadata, &child_fn_lock, &lock);
ASSERT_NE(pid, -1);
pthread_barrier_wait(&barrier);
@@ -238,9 +252,7 @@ TEST(test_robustness)
wait(&wstatus);
pthread_barrier_destroy(&barrier);
- /* Pass only if the child hasn't return error */
- if (!WEXITSTATUS(wstatus))
- ksft_test_result_pass("%s\n", __func__);
+ EXPECT_EQ(WEXITSTATUS(wstatus), 0) TH_LOG("child failed");
}
/*
@@ -266,8 +278,6 @@ TEST(test_set_robust_list_invalid_size)
ret = set_robust_list(&head, 0);
ASSERT_EQ(ret, -1);
ASSERT_EQ(errno, EINVAL);
-
- ksft_test_result_pass("%s\n", __func__);
}
/*
@@ -294,20 +304,19 @@ TEST(test_get_robust_list_self)
ASSERT_EQ(ret, 0);
ASSERT_EQ(get_head, &head2);
ASSERT_EQ(head_size, len_ptr);
-
- ksft_test_result_pass("%s\n", __func__);
}
static int child_list(void *arg)
{
- struct robust_list_head *head = arg;
+ struct child_args *cargs = arg;
+ struct __test_metadata *_metadata = cargs->_metadata;
+ struct robust_list_head *head = cargs->arg;
int ret;
+ free(cargs);
+
ret = set_robust_list(head, sizeof(*head));
- if (ret) {
- ksft_test_result_fail("set_robust_list error\n");
- return -1;
- }
+ ASSERT_EQ(ret, 0) TH_LOG("set_robust_list error");
/*
* After setting the list head, wait until the main thread can call
@@ -337,7 +346,7 @@ TEST(test_get_robust_list_child)
ret = pthread_barrier_init(&barrier2, NULL, 2);
ASSERT_EQ(ret, 0);
- tid = create_child(&child_list, &head);
+ tid = create_child(_metadata, &child_list, &head);
ASSERT_NE(tid, -1);
pthread_barrier_wait(&barrier);
@@ -352,28 +361,24 @@ TEST(test_get_robust_list_child)
pthread_barrier_destroy(&barrier);
pthread_barrier_destroy(&barrier2);
- /* Pass only if the child hasn't return error */
- if (!WEXITSTATUS(wstatus))
- ksft_test_result_pass("%s\n", __func__);
+ EXPECT_EQ(WEXITSTATUS(wstatus), 0) TH_LOG("child failed");
}
static int child_fn_lock_with_error(void *arg)
{
- struct lock_struct *lock = arg;
+ struct child_args *cargs = arg;
+ struct __test_metadata *_metadata = cargs->_metadata;
+ struct lock_struct *lock = cargs->arg;
struct robust_list_head head;
int ret;
+ free(cargs);
+
ret = set_list(&head);
- if (ret) {
- ksft_test_result_fail("set_robust_list error\n");
- return -1;
- }
+ ASSERT_EQ(ret, 0) TH_LOG("set_robust_list error");
ret = mutex_lock(lock, &head, true);
- if (ret) {
- ksft_test_result_fail("mutex_lock error\n");
- return -1;
- }
+ ASSERT_EQ(ret, 0) TH_LOG("mutex_lock error");
pthread_barrier_wait(&barrier);
@@ -391,7 +396,7 @@ static int child_fn_lock_with_error(void *arg)
TEST(test_set_list_op_pending)
{
struct lock_struct lock = { .futex = 0 };
- _Atomic(unsigned int) *futex = &lock.futex;
+ atomic_futex_t *futex = &lock.futex;
struct robust_list_head head;
int ret, wstatus;
@@ -401,7 +406,7 @@ TEST(test_set_list_op_pending)
ret = pthread_barrier_init(&barrier, NULL, 2);
ASSERT_EQ(ret, 0);
- ret = create_child(&child_fn_lock_with_error, &lock);
+ ret = create_child(_metadata, &child_fn_lock_with_error, &lock);
ASSERT_NE(ret, -1);
pthread_barrier_wait(&barrier);
@@ -414,21 +419,21 @@ TEST(test_set_list_op_pending)
wait(&wstatus);
pthread_barrier_destroy(&barrier);
- /* Pass only if the child hasn't return error */
- if (!WEXITSTATUS(wstatus))
- ksft_test_result_pass("%s\n", __func__);
- else
- ksft_test_result_fail("%s\n", __func__);
+ EXPECT_EQ(WEXITSTATUS(wstatus), 0) TH_LOG("child failed");
}
#define CHILD_NR 10
static int child_lock_holder(void *arg)
{
- struct lock_struct *locks = arg;
+ struct child_args *cargs = arg;
+ struct __test_metadata *_metadata = cargs->_metadata;
+ struct lock_struct *locks = cargs->arg;
struct robust_list_head head;
int i;
+ free(cargs);
+
set_list(&head);
for (i = 0; i < CHILD_NR; i++) {
@@ -447,22 +452,20 @@ static int child_lock_holder(void *arg)
static int child_wait_lock(void *arg)
{
- struct lock_struct *lock = arg;
+ struct child_args *cargs = arg;
+ struct __test_metadata *_metadata = cargs->_metadata;
+ struct lock_struct *lock = cargs->arg;
struct robust_list_head head;
int ret;
+ free(cargs);
+
pthread_barrier_wait(&barrier2);
ret = mutex_lock(lock, &head, false);
+ ASSERT_EQ(ret, 0) TH_LOG("mutex_lock error");
- if (ret) {
- ksft_test_result_fail("mutex_lock error\n");
- return -1;
- }
-
- if (!(lock->futex & FUTEX_OWNER_DIED)) {
- ksft_test_result_fail("futex not marked with FUTEX_OWNER_DIED\n");
- return -1;
- }
+ ASSERT_TRUE(lock->futex & FUTEX_OWNER_DIED)
+ TH_LOG("futex not marked with FUTEX_OWNER_DIED");
return 0;
}
@@ -482,18 +485,20 @@ TEST(test_robust_list_multiple_elements)
ret = pthread_barrier_init(&barrier2, NULL, CHILD_NR + 1);
ASSERT_EQ(ret, 0);
- pids[0] = create_child(&child_lock_holder, &locks);
+ pids[0] = create_child(_metadata, &child_lock_holder, &locks);
+ ASSERT_NE(pids[0], -1);
/* Wait until the locker thread takes the look */
pthread_barrier_wait(&barrier);
- for (i = 0; i < CHILD_NR; i++)
- pids[i+1] = create_child(&child_wait_lock, &locks[i]);
+ for (i = 0; i < CHILD_NR; i++) {
+ pids[i+1] = create_child(_metadata, &child_wait_lock, &locks[i]);
+ ASSERT_NE(pids[i+1], -1);
+ }
- /* Wait for all children to return */
+ /* Wait for all children to return (holder + all waiters) */
ret = 0;
-
- for (i = 0; i < CHILD_NR; i++) {
+ for (i = 0; i < CHILD_NR + 1; i++) {
waitpid(pids[i], &wstatus, 0);
if (WEXITSTATUS(wstatus))
ret = -1;
@@ -502,22 +507,21 @@ TEST(test_robust_list_multiple_elements)
pthread_barrier_destroy(&barrier);
pthread_barrier_destroy(&barrier2);
- /* Pass only if the child hasn't return error */
- if (!ret)
- ksft_test_result_pass("%s\n", __func__);
+ EXPECT_EQ(ret, 0) TH_LOG("One or more children failed");
}
static int child_circular_list(void *arg)
{
+ struct child_args *cargs = arg;
+ struct __test_metadata *_metadata = cargs->_metadata;
static struct robust_list_head head;
struct lock_struct a, b, c;
int ret;
+ free(cargs);
+
ret = set_list(&head);
- if (ret) {
- ksft_test_result_fail("set_list error\n");
- return -1;
- }
+ ASSERT_EQ(ret, 0) TH_LOG("set_list error");
head.list.next = &a.list;
@@ -539,14 +543,14 @@ static int child_circular_list(void *arg)
TEST(test_circular_list)
{
int wstatus;
+ pid_t pid;
- create_child(child_circular_list, NULL);
+ pid = create_child(_metadata, child_circular_list, NULL);
+ ASSERT_NE(pid, -1);
wait(&wstatus);
- /* Pass only if the child hasn't return error */
- if (!WEXITSTATUS(wstatus))
- ksft_test_result_pass("%s\n", __func__);
+ EXPECT_EQ(WEXITSTATUS(wstatus), 0) TH_LOG("child failed");
}
TEST_HARNESS_MAIN
--
2.54.0.823.g6e5bcc1fc9-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [tip: locking/futex] selftests/futex: Migrate robust_list to harness
2026-06-01 6:51 ` [PATCH 7/7] selftests/futex: Migrate robust_list " Wake Liu
@ 2026-07-05 19:54 ` tip-bot2 for Wake Liu
0 siblings, 0 replies; 17+ messages in thread
From: tip-bot2 for Wake Liu @ 2026-07-05 19:54 UTC (permalink / raw)
To: linux-tip-commits; +Cc: Wake Liu, Thomas Gleixner, x86, linux-kernel
The following commit has been merged into the locking/futex branch of tip:
Commit-ID: 553bd67a903273d94030f32d671f3d6f19860a85
Gitweb: https://git.kernel.org/tip/553bd67a903273d94030f32d671f3d6f19860a85
Author: Wake Liu <wakel@google.com>
AuthorDate: Mon, 01 Jun 2026 06:51:26
Committer: Thomas Gleixner <tglx@kernel.org>
CommitterDate: Sun, 05 Jul 2026 21:49:18 +02:00
selftests/futex: Migrate robust_list to harness
Migrate robust_list test to the kselftest harness framework, removing mixed
legacy ksft_* API usages and passing test metadata to cloned child
functions via child_args struct.
Also, fix an out-of-bounds waitpid bug during multithreaded tests.
[ tglx: Fixup coding style ]
Signed-off-by: Wake Liu <wakel@google.com>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260601065126.3623867-8-wakel@google.com
---
tools/testing/selftests/futex/functional/robust_list.c | 179 ++++----
1 file changed, 97 insertions(+), 82 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/robust_list.c b/tools/testing/selftests/futex/functional/robust_list.c
index 12feec1..3f713bd 100644
--- a/tools/testing/selftests/futex/functional/robust_list.c
+++ b/tools/testing/selftests/futex/functional/robust_list.c
@@ -25,24 +25,24 @@
#define _GNU_SOURCE
#include "futextest.h"
-#include "../../kselftest_harness.h"
+#include "kselftest_harness.h"
#include <dlfcn.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
-#include <stdint.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/auxv.h>
#include <sys/mman.h>
#include <sys/wait.h>
#define STACK_SIZE (1024 * 1024)
-
#define FUTEX_TIMEOUT 3
-
#define SLEEP_US 100
#if __SIZEOF_LONG__ == 8
@@ -71,30 +71,46 @@ static int sys_futex_robust_unlock(_Atomic(uint32_t) *uaddr, unsigned int op, in
* Basic lock struct, contains just the futex word and the robust list element
* Real implementations have also a *prev to easily walk in the list
*/
+typedef _Atomic(unsigned int) atomic_futex_t;
+
struct lock_struct {
- _Atomic(unsigned int) futex;
+ atomic_futex_t futex;
struct robust_list list;
};
+struct child_args {
+ struct __test_metadata *_metadata;
+ void *arg;
+};
+
/*
* Helper function to spawn a child thread. Returns -1 on error, pid on success
*/
-static int create_child(int (*fn)(void *arg), void *arg)
+static int create_child(struct __test_metadata *_metadata, int (*fn)(void *arg), void *arg)
{
+ struct child_args *cargs = malloc(sizeof(*cargs));
char *stack;
pid_t pid;
+ if (!cargs)
+ return -1;
+ cargs->_metadata = _metadata;
+ cargs->arg = arg;
+
stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
- if (stack == MAP_FAILED)
+ if (stack == MAP_FAILED) {
+ free(cargs);
return -1;
+ }
stack += STACK_SIZE;
- pid = clone(fn, stack, CLONE_VM | SIGCHLD, arg);
-
- if (pid == -1)
+ pid = clone(fn, stack, CLONE_VM | SIGCHLD, cargs);
+ if (pid == -1) {
+ free(cargs);
return -1;
+ }
return pid;
}
@@ -123,7 +139,7 @@ static int set_list(struct robust_list_head *head)
*/
static int mutex_lock(struct lock_struct *lock, struct robust_list_head *head, bool error_inject)
{
- _Atomic(unsigned int) *futex = &lock->futex;
+ atomic_futex_t *futex = &lock->futex;
unsigned int zero = 0;
pid_t tid = gettid();
int ret = -1;
@@ -183,21 +199,21 @@ static int mutex_lock(struct lock_struct *lock, struct robust_list_head *head, b
*/
static int child_fn_lock(void *arg)
{
- struct lock_struct *lock = arg;
+ struct child_args *cargs = arg;
+ struct __test_metadata *_metadata = cargs->_metadata;
+ struct lock_struct *lock = cargs->arg;
struct robust_list_head head;
int ret;
+ free(cargs);
+
ret = set_list(&head);
- if (ret) {
- ksft_test_result_fail("set_robust_list error\n");
- return ret;
- }
+ ASSERT_EQ(ret, 0)
+ TH_LOG("set_robust_list error");
ret = mutex_lock(lock, &head, false);
- if (ret) {
- ksft_test_result_fail("mutex_lock error\n");
- return ret;
- }
+ ASSERT_EQ(ret, 0)
+ TH_LOG("mutex_lock error");
pthread_barrier_wait(&barrier);
@@ -220,7 +236,7 @@ static int child_fn_lock(void *arg)
TEST(test_robustness)
{
struct lock_struct lock = { .futex = 0 };
- _Atomic(unsigned int) *futex = &lock.futex;
+ atomic_futex_t *futex = &lock.futex;
struct robust_list_head head;
int ret, pid, wstatus;
@@ -234,7 +250,7 @@ TEST(test_robustness)
ret = pthread_barrier_init(&barrier, NULL, 2);
ASSERT_EQ(ret, 0);
- pid = create_child(&child_fn_lock, &lock);
+ pid = create_child(_metadata, &child_fn_lock, &lock);
ASSERT_NE(pid, -1);
pthread_barrier_wait(&barrier);
@@ -251,9 +267,8 @@ TEST(test_robustness)
wait(&wstatus);
pthread_barrier_destroy(&barrier);
- /* Pass only if the child hasn't return error */
- if (!WEXITSTATUS(wstatus))
- ksft_test_result_pass("%s\n", __func__);
+ EXPECT_EQ(WEXITSTATUS(wstatus), 0)
+ TH_LOG("child failed");
}
/*
@@ -279,8 +294,6 @@ TEST(test_set_robust_list_invalid_size)
ret = set_robust_list(&head, 0);
ASSERT_EQ(ret, -1);
ASSERT_EQ(errno, EINVAL);
-
- ksft_test_result_pass("%s\n", __func__);
}
/*
@@ -307,20 +320,20 @@ TEST(test_get_robust_list_self)
ASSERT_EQ(ret, 0);
ASSERT_EQ(get_head, &head2);
ASSERT_EQ(head_size, len_ptr);
-
- ksft_test_result_pass("%s\n", __func__);
}
static int child_list(void *arg)
{
- struct robust_list_head *head = arg;
+ struct child_args *cargs = arg;
+ struct __test_metadata *_metadata = cargs->_metadata;
+ struct robust_list_head *head = cargs->arg;
int ret;
+ free(cargs);
+
ret = set_robust_list(head, sizeof(*head));
- if (ret) {
- ksft_test_result_fail("set_robust_list error\n");
- return -1;
- }
+ ASSERT_EQ(ret, 0)
+ TH_LOG("set_robust_list error");
/*
* After setting the list head, wait until the main thread can call
@@ -350,7 +363,7 @@ TEST(test_get_robust_list_child)
ret = pthread_barrier_init(&barrier2, NULL, 2);
ASSERT_EQ(ret, 0);
- tid = create_child(&child_list, &head);
+ tid = create_child(_metadata, &child_list, &head);
ASSERT_NE(tid, -1);
pthread_barrier_wait(&barrier);
@@ -365,28 +378,27 @@ TEST(test_get_robust_list_child)
pthread_barrier_destroy(&barrier);
pthread_barrier_destroy(&barrier2);
- /* Pass only if the child hasn't return error */
- if (!WEXITSTATUS(wstatus))
- ksft_test_result_pass("%s\n", __func__);
+ EXPECT_EQ(WEXITSTATUS(wstatus), 0)
+ TH_LOG("child failed");
}
static int child_fn_lock_with_error(void *arg)
{
- struct lock_struct *lock = arg;
+ struct child_args *cargs = arg;
+ struct __test_metadata *_metadata = cargs->_metadata;
+ struct lock_struct *lock = cargs->arg;
struct robust_list_head head;
int ret;
+ free(cargs);
+
ret = set_list(&head);
- if (ret) {
- ksft_test_result_fail("set_robust_list error\n");
- return -1;
- }
+ ASSERT_EQ(ret, 0)
+ TH_LOG("set_robust_list error");
ret = mutex_lock(lock, &head, true);
- if (ret) {
- ksft_test_result_fail("mutex_lock error\n");
- return -1;
- }
+ ASSERT_EQ(ret, 0)
+ TH_LOG("mutex_lock error");
pthread_barrier_wait(&barrier);
@@ -404,7 +416,7 @@ static int child_fn_lock_with_error(void *arg)
TEST(test_set_list_op_pending)
{
struct lock_struct lock = { .futex = 0 };
- _Atomic(unsigned int) *futex = &lock.futex;
+ atomic_futex_t *futex = &lock.futex;
struct robust_list_head head;
int ret, wstatus;
@@ -414,7 +426,7 @@ TEST(test_set_list_op_pending)
ret = pthread_barrier_init(&barrier, NULL, 2);
ASSERT_EQ(ret, 0);
- ret = create_child(&child_fn_lock_with_error, &lock);
+ ret = create_child(_metadata, &child_fn_lock_with_error, &lock);
ASSERT_NE(ret, -1);
pthread_barrier_wait(&barrier);
@@ -427,21 +439,21 @@ TEST(test_set_list_op_pending)
wait(&wstatus);
pthread_barrier_destroy(&barrier);
- /* Pass only if the child hasn't return error */
- if (!WEXITSTATUS(wstatus))
- ksft_test_result_pass("%s\n", __func__);
- else
- ksft_test_result_fail("%s\n", __func__);
+ EXPECT_EQ(WEXITSTATUS(wstatus), 0)
+ TH_LOG("child failed");
}
#define CHILD_NR 10
static int child_lock_holder(void *arg)
{
- struct lock_struct *locks = arg;
+ struct child_args *cargs = arg;
+ struct lock_struct *locks = cargs->arg;
struct robust_list_head head;
int i;
+ free(cargs);
+
set_list(&head);
for (i = 0; i < CHILD_NR; i++) {
@@ -460,22 +472,21 @@ static int child_lock_holder(void *arg)
static int child_wait_lock(void *arg)
{
- struct lock_struct *lock = arg;
+ struct child_args *cargs = arg;
+ struct __test_metadata *_metadata = cargs->_metadata;
+ struct lock_struct *lock = cargs->arg;
struct robust_list_head head;
int ret;
+ free(cargs);
+
pthread_barrier_wait(&barrier2);
ret = mutex_lock(lock, &head, false);
+ ASSERT_EQ(ret, 0)
+ TH_LOG("mutex_lock error");
- if (ret) {
- ksft_test_result_fail("mutex_lock error\n");
- return -1;
- }
-
- if (!(lock->futex & FUTEX_OWNER_DIED)) {
- ksft_test_result_fail("futex not marked with FUTEX_OWNER_DIED\n");
- return -1;
- }
+ ASSERT_TRUE(lock->futex & FUTEX_OWNER_DIED)
+ TH_LOG("futex not marked with FUTEX_OWNER_DIED");
return 0;
}
@@ -495,18 +506,20 @@ TEST(test_robust_list_multiple_elements)
ret = pthread_barrier_init(&barrier2, NULL, CHILD_NR + 1);
ASSERT_EQ(ret, 0);
- pids[0] = create_child(&child_lock_holder, &locks);
+ pids[0] = create_child(_metadata, &child_lock_holder, &locks);
+ ASSERT_NE(pids[0], -1);
/* Wait until the locker thread takes the look */
pthread_barrier_wait(&barrier);
- for (i = 0; i < CHILD_NR; i++)
- pids[i+1] = create_child(&child_wait_lock, &locks[i]);
+ for (i = 0; i < CHILD_NR; i++) {
+ pids[i+1] = create_child(_metadata, &child_wait_lock, &locks[i]);
+ ASSERT_NE(pids[i+1], -1);
+ }
- /* Wait for all children to return */
+ /* Wait for all children to return (holder + all waiters) */
ret = 0;
-
- for (i = 0; i < CHILD_NR; i++) {
+ for (i = 0; i < CHILD_NR + 1; i++) {
waitpid(pids[i], &wstatus, 0);
if (WEXITSTATUS(wstatus))
ret = -1;
@@ -515,22 +528,23 @@ TEST(test_robust_list_multiple_elements)
pthread_barrier_destroy(&barrier);
pthread_barrier_destroy(&barrier2);
- /* Pass only if the child hasn't return error */
- if (!ret)
- ksft_test_result_pass("%s\n", __func__);
+ EXPECT_EQ(ret, 0)
+ TH_LOG("One or more children failed");
}
static int child_circular_list(void *arg)
{
+ struct child_args *cargs = arg;
+ struct __test_metadata *_metadata = cargs->_metadata;
struct robust_list_head head;
struct lock_struct a, b, c;
int ret;
+ free(cargs);
+
ret = set_list(&head);
- if (ret) {
- ksft_test_result_fail("set_list error\n");
- return -1;
- }
+ ASSERT_EQ(ret, 0)
+ TH_LOG("set_list error");
head.list.next = &a.list;
@@ -552,14 +566,15 @@ static int child_circular_list(void *arg)
TEST(test_circular_list)
{
int wstatus;
+ pid_t pid;
- create_child(child_circular_list, NULL);
+ pid = create_child(_metadata, child_circular_list, NULL);
+ ASSERT_NE(pid, -1);
wait(&wstatus);
- /* Pass only if the child hasn't return error */
- if (!WEXITSTATUS(wstatus))
- ksft_test_result_pass("%s\n", __func__);
+ EXPECT_EQ(WEXITSTATUS(wstatus), 0)
+ TH_LOG("child failed");
}
/*
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 0/7] selftests/futex: Migrate requeue, NUMA and robust list tests to harness
2026-06-01 6:51 [PATCH 0/7] selftests/futex: Migrate requeue, NUMA and robust list tests to harness Wake Liu
` (6 preceding siblings ...)
2026-06-01 6:51 ` [PATCH 7/7] selftests/futex: Migrate robust_list " Wake Liu
@ 2026-06-01 8:24 ` Peter Zijlstra
2026-06-03 6:17 ` Wake Liu
7 siblings, 1 reply; 17+ messages in thread
From: Peter Zijlstra @ 2026-06-01 8:24 UTC (permalink / raw)
To: Wake Liu
Cc: Thomas Gleixner, Ingo Molnar, Shuah Khan, linux-kselftest,
Darren Hart, Davidlohr Bueso, André Almeida, Carlos Llamas,
linux-kernel
On Mon, Jun 01, 2026 at 06:51:19AM +0000, Wake Liu wrote:
> This series refactors the requeue, NUMA, and robust list futex functional
> tests to exclusively use the kselftest_harness.h framework, completing
> the remaining unsent functional test migrations in this directory.
>
> This eliminates mixed usage of legacy ksft_* APIs and high-level harness
> asserts, preventing crashes on older kernels, and ensures proper thread
> joining.
>
> For context, the previous wait-related migrations are in these states:
> - Series 1 v2 (wait_timeout, wait_wouldblock, waitv): Sent, awaiting review.
> Link: https://lore.kernel.org/linux-kselftest/20260526010635.23980-1-wakel@google.com/
> - Series 2 v1 (wait, private_mapped, uninitialized_heap): Sent, discussion ongoing.
> Link: https://lore.kernel.org/linux-kselftest/20260525092002.3762888-1-wakel@google.com/
>
> Descriptions of individual patches:
> Patch 1-4: Migrate requeue, requeue_pi, mismatched_ops, and signal_restart tests.
> Patch 5: Migrates futex_numa_mpol.
> Patch 6: Migrates futex_priv_hash.
> Patch 7: Migrates robust_list (and fixes an out-of-bounds waitpid bug).
Does this affect being able to build tools/testing/selftests/futex/
without having to do the ludicrous batshit 'make headers' thing?
If I cannot build the futex selftests in a virgin tree, then they're
broken. The selftests maintainers have time and time again shown their
incompetence and I'm sick of it.
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH 0/7] selftests/futex: Migrate requeue, NUMA and robust list tests to harness
2026-06-01 8:24 ` [PATCH 0/7] selftests/futex: Migrate requeue, NUMA and robust list tests " Peter Zijlstra
@ 2026-06-03 6:17 ` Wake Liu
0 siblings, 0 replies; 17+ messages in thread
From: Wake Liu @ 2026-06-03 6:17 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Thomas Gleixner, Ingo Molnar, Shuah Khan, linux-kselftest,
Darren Hart, Davidlohr Bueso, André Almeida, Carlos Llamas,
linux-kernel
On Mon, Jun 01, 2026 at 08:24:06AM +0000, Peter Zijlstra wrote:
> Does this affect being able to build tools/testing/selftests/futex/
> without having to do the ludicrous batshit 'make headers' thing?
No, this series does not affect the ability to build the futex selftests
without 'make headers'.
The refactoring only touches the test logic and assertions to use the
kselftest harness, and does not introduce any new UAPI header dependencies.
All recent futex/prctl UAPI definitions (like futex_waitv, FUTEX2_* flags,
and PR_FUTEX_HASH) are already guarded with fallback defines in futextest.h,
futex2test.h, and the test files themselves.
It compiles fine in a virgin tree using the host's system headers,
exactly as it did before.
> If I cannot build the futex selftests in a virgin tree, then they're
> broken. The selftests maintainers have time and time again shown their
> incompetence and I'm sick of it.
--
Best Regards,
Wake Liu
^ permalink raw reply [flat|nested] 17+ messages in thread