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] selftests/futex: Retry the wake in futex_wait instead of sleeping
Date: Sun, 8 Nov 2026 09:23:09 -0500 [thread overview]
Message-ID: <20261108142309.1527337-1-mathieu.desnoyers@efficios.com> (raw)
Each futex_wait test starts a waiter thread, which calls futex_wait()
with a 30ms timeout. The main thread sleeps 10ms, then expects
futex_wake() to wake one waiter. So the test assumes that the waiter
reaches futex_wait() within 10ms, and that the main thread runs again
within 30ms.
A busy machine breaks both. The built-in locktorture at times holds a
spinlock for 100ms with preemption off. With it, private_futex failed in
about 0.5% of the runs in 8-CPU VMs, on v7.4-rc1.
Timestamps showed two cases. The waiter started up to 75ms late, after
the wake. Or the main thread woke up to 105ms late, after the waiter
had timed out.
Fix this by retrying futex_wake() every millisecond until it wakes the
waiter, for up to 5s. Give the waiter a timeout of 10s, so that it
outlasts the retries. The tests then wait for the waiter, instead of
assuming when it runs.
With this patch, private_futex passed 6000 runs of 6000 in the same VMs,
and the three tests 2000 runs of 2000.
Fixes: c3d128581f64 ("selftests: futex: Add futex wait test")
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
---
.../selftests/futex/functional/futex_wait.c | 39 ++++++++++++-------
1 file changed, 26 insertions(+), 13 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/futex_wait.c b/tools/testing/selftests/futex/functional/futex_wait.c
index 5292f5d2c3b5..e7ebc7d8be1d 100644
--- a/tools/testing/selftests/futex/functional/futex_wait.c
+++ b/tools/testing/selftests/futex/functional/futex_wait.c
@@ -14,8 +14,9 @@
#include "futextest.h"
#include "kselftest_harness.h"
-#define timeout_ns 30000000
-#define WAKE_WAIT_US 10000
+#define WAIT_TIMEOUT_S 10
+#define WAKE_RETRY_US 1000
+#define WAKE_TRIES 5000
#define SHM_PATH "futex_shm_file"
void *futex;
@@ -32,8 +33,8 @@ static void *waiterfn(void *arg)
struct timespec to;
int res;
- to.tv_sec = 0;
- to.tv_nsec = timeout_ns;
+ to.tv_sec = WAIT_TIMEOUT_S;
+ to.tv_nsec = 0;
res = futex_wait(futex, 0, &to, args->flags);
if (res) {
@@ -45,6 +46,24 @@ static void *waiterfn(void *arg)
return NULL;
}
+/*
+ * Wake the waiter of @uaddr. The waiter thread may not have reached
+ * futex_wait() yet, so retry until futex_wake() wakes it, for up to
+ * WAKE_TRIES times WAKE_RETRY_US. Return what futex_wake() last returned.
+ */
+static int wake_waiter(void *uaddr, unsigned int flags)
+{
+ int i, res = 0;
+
+ for (i = 0; i < WAKE_TRIES; i++) {
+ res = futex_wake(uaddr, 1, flags);
+ if (res)
+ break;
+ usleep(WAKE_RETRY_US);
+ }
+ return res;
+}
+
TEST(private_futex)
{
struct waiter_args *args = malloc(sizeof(*args));
@@ -61,10 +80,8 @@ TEST(private_futex)
ASSERT_EQ(pthread_create(&waiter, NULL, waiterfn, args), 0)
TH_LOG("pthread_create failed");
- usleep(WAKE_WAIT_US);
-
TH_LOG("Calling private futex_wake on futex: %p", futex);
- res = futex_wake(futex, 1, FUTEX_PRIVATE_FLAG);
+ res = wake_waiter(futex, FUTEX_PRIVATE_FLAG);
EXPECT_EQ(res, 1)
TH_LOG("futex_wake private returned: %d %s", res, res < 0 ? strerror(errno) : "");
@@ -106,10 +123,8 @@ TEST(anon_page)
ASSERT_EQ(pthread_create(&waiter, NULL, waiterfn, args), 0)
TH_LOG("pthread_create failed");
- usleep(WAKE_WAIT_US);
-
TH_LOG("Calling shared (page anon) futex_wake on futex: %p", futex);
- res = futex_wake(futex, 1, 0);
+ res = wake_waiter(futex, 0);
EXPECT_EQ(res, 1) {
TH_LOG("futex_wake shared (page anon) returned: %d %s",
res, res < 0 ? strerror(errno) : "");
@@ -161,10 +176,8 @@ TEST(file_backed)
ASSERT_EQ(pthread_create(&waiter, NULL, waiterfn, args), 0)
TH_LOG("pthread_create failed");
- usleep(WAKE_WAIT_US);
-
TH_LOG("Calling shared (file backed) futex_wake on futex: %p", futex);
- res = futex_wake(shm, 1, 0);
+ res = wake_waiter(shm, 0);
EXPECT_EQ(res, 1) {
TH_LOG("futex_wake shared (file backed) returned: %d %s",
res, res < 0 ? strerror(errno) : "");
base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
--
2.47.3
next reply other threads:[~2026-11-08 14:23 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-08 14:23 Mathieu Desnoyers [this message]
2026-11-08 14:34 ` 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=20261108142309.1527337-1-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®