mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
To: tglx@kernel.org, mingo@redhat.com, peterz@infradead.org
Cc: linux-kernel@vger.kernel.org,
	Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
	dvhart@infradead.org, dave@stgolabs.net, andrealmeid@igalia.com,
	shuah@kernel.org, linux-kselftest@vger.kernel.org
Subject: [PATCH v2 3/4] selftests/futex: Retry the wake in futex_waitv instead of sleeping
Date: Sun,  8 Nov 2026 09:49:51 -0500	[thread overview]
Message-ID: <20261108144952.1531160-4-mathieu.desnoyers@efficios.com> (raw)
In-Reply-To: <20261108144952.1531160-1-mathieu.desnoyers@efficios.com>

The private_waitv and shared_waitv tests start a waiter thread, which
calls futex_waitv() with a timeout of 1s. The main thread sleeps 10ms,
then expects futex_wake() to wake that waiter. So the test assumes that
the waiter reaches futex_waitv() within 10ms.

A busy machine breaks this. The built-in locktorture at times holds a
spinlock for 100ms with preemption off. With it, the tests of
futex_waitv failed in about 1% of the runs in 8-CPU VMs, on v7.4-rc1.
In each failure, futex_wake() found no waiter in private_waitv or
shared_waitv.

The two tests also do not join the waiter. A test can then end before
the waiter checks what futex_waitv() returned.

Fix this as the previous patch does for futex_wait. The waiter sets a
flag once futex_waitv() returns. The main thread retries futex_wake()
every millisecond until it sees that flag, and expects one waiter woken
in all. The waiter waits without a timeout. If a wake is lost, the
timeout of the kselftest harness ends the test. Join the waiter at the
end of each test, and check that the join succeeds.

With this patch, the tests passed 4000 runs of 4000 in the same VMs.

Fixes: 5e59c1d1c78c ("selftests: futex: Add sys_futex_waitv() test")
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
---
 .../selftests/futex/functional/futex_waitv.c  | 50 +++++++++++++------
 1 file changed, 35 insertions(+), 15 deletions(-)

diff --git a/tools/testing/selftests/futex/functional/futex_waitv.c b/tools/testing/selftests/futex/functional/futex_waitv.c
index 4858d5faeecf..ccfa31fd20fa 100644
--- a/tools/testing/selftests/futex/functional/futex_waitv.c
+++ b/tools/testing/selftests/futex/functional/futex_waitv.c
@@ -20,25 +20,20 @@
 #include "futex2test.h"
 #include "kselftest_harness.h"
 
-#define WAKE_WAIT_US 10000
+#define WAKE_RETRY_US 1000
 #define NR_FUTEXES 30
 static struct futex_waitv waitv[NR_FUTEXES];
 u_int32_t futexes[NR_FUTEXES] = {0};
+static int waiter_done;
 
 
 void *waiterfn(void *arg)
 {
 	struct __test_metadata *_metadata = (struct __test_metadata *)arg;
-	struct timespec to;
 	int res;
 
-	/* setting absolute timeout for futex2 */
-	ASSERT_EQ(clock_gettime(CLOCK_MONOTONIC, &to), 0)
-		TH_LOG("gettime64 failed");
-
-	to.tv_sec++;
-
-	res = futex_waitv(waitv, NR_FUTEXES, 0, &to, CLOCK_MONOTONIC);
+	res = futex_waitv(waitv, NR_FUTEXES, 0, NULL, CLOCK_MONOTONIC);
+	__atomic_store_n(&waiter_done, 1, __ATOMIC_RELEASE);
 	if (res < 0) {
 		EXPECT_EQ(res, NR_FUTEXES - 1)
 			TH_LOG("futex_waitv failed: %s", strerror(errno));
@@ -50,6 +45,25 @@ void *waiterfn(void *arg)
 	return NULL;
 }
 
+/*
+ * Wake the waiter of @uaddr until it has returned from futex_waitv(). The
+ * waiter may not have reached futex_waitv() yet, and a wake then finds no
+ * waiter. Return how many waiters futex_wake() woke, or -1 on error.
+ */
+static int wake_waiter(void *uaddr, unsigned int flags)
+{
+	int res, woken = 0;
+
+	while (!__atomic_load_n(&waiter_done, __ATOMIC_ACQUIRE)) {
+		res = futex_wake(uaddr, 1, flags);
+		if (res < 0)
+			return res;
+		woken += res;
+		usleep(WAKE_RETRY_US);
+	}
+	return woken;
+}
+
 TEST(private_waitv)
 {
 	pthread_t waiter;
@@ -66,14 +80,17 @@ TEST(private_waitv)
 	}
 
 	/* Private waitv */
+	waiter_done = 0;
 	ASSERT_EQ(pthread_create(&waiter, NULL, waiterfn, _metadata), 0)
 		TH_LOG("pthread_create failed");
 
-	usleep(WAKE_WAIT_US);
-
-	res = futex_wake(u64_to_ptr(waitv[NR_FUTEXES - 1].uaddr), 1, FUTEX_PRIVATE_FLAG);
+	res = wake_waiter(u64_to_ptr(waitv[NR_FUTEXES - 1].uaddr), FUTEX_PRIVATE_FLAG);
 	EXPECT_EQ(res, 1)
 		TH_LOG("futex_wake private returned: %d %s", res, res < 0 ? strerror(errno) : "");
+
+	res = pthread_join(waiter, NULL);
+	EXPECT_EQ(res, 0)
+		TH_LOG("pthread_join failed: %s", strerror(res));
 }
 
 TEST(shared_waitv)
@@ -104,15 +121,18 @@ TEST(shared_waitv)
 		waitv[i].__reserved = 0;
 	}
 
+	waiter_done = 0;
 	ASSERT_EQ(pthread_create(&waiter, NULL, waiterfn, _metadata), 0)
 		TH_LOG("pthread_create failed");
 
-	usleep(WAKE_WAIT_US);
-
-	res = futex_wake(u64_to_ptr(waitv[NR_FUTEXES - 1].uaddr), 1, 0);
+	res = wake_waiter(u64_to_ptr(waitv[NR_FUTEXES - 1].uaddr), 0);
 	EXPECT_EQ(res, 1)
 		TH_LOG("futex_wake shared returned: %d %s", res, res < 0 ? strerror(errno) : "");
 
+	res = pthread_join(waiter, NULL);
+	EXPECT_EQ(res, 0)
+		TH_LOG("pthread_join failed: %s", strerror(res));
+
 	for (i = 0; i < NR_FUTEXES; i++)
 		shmdt(u64_to_ptr(waitv[i].uaddr));
 }
-- 
2.47.3


  parent reply	other threads:[~2026-11-08 14:49 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-08 14:49 [PATCH v2 0/4] selftests/futex: Fix flaky futex_wait and futex_waitv tests Mathieu Desnoyers
2026-11-08 14:49 ` [PATCH v2 1/4] selftests/futex: Let futex_waitv() take no timeout Mathieu Desnoyers
2026-11-08 14:49 ` [PATCH v2 2/4] selftests/futex: Retry the wake in futex_wait instead of sleeping Mathieu Desnoyers
2026-11-08 14:49 ` Mathieu Desnoyers [this message]
2026-11-08 14:49 ` [PATCH v2 4/4] selftests/futex: Remove the shared memory segments of the futex tests Mathieu Desnoyers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261108144952.1531160-4-mathieu.desnoyers@efficios.com \
    --to=mathieu.desnoyers@efficios.com \
    --cc=andrealmeid@igalia.com \
    --cc=dave@stgolabs.net \
    --cc=dvhart@infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=peterz@infradead.org \
    --cc=shuah@kernel.org \
    --cc=tglx@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®