* [PATCH] selftests/futex: Retry the wake in futex_wait instead of sleeping
@ 2026-11-08 14:23 Mathieu Desnoyers
2026-11-08 14:34 ` Mathieu Desnoyers
0 siblings, 1 reply; 2+ messages in thread
From: Mathieu Desnoyers @ 2026-11-08 14:23 UTC (permalink / raw)
To: tglx, mingo, peterz
Cc: linux-kernel, Mathieu Desnoyers, dvhart, dave, andrealmeid,
shuah, linux-kselftest
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
^ permalink raw reply [flat|nested] 2+ messages in thread* Re: [PATCH] selftests/futex: Retry the wake in futex_wait instead of sleeping
2026-11-08 14:23 [PATCH] selftests/futex: Retry the wake in futex_wait instead of sleeping Mathieu Desnoyers
@ 2026-11-08 14:34 ` Mathieu Desnoyers
0 siblings, 0 replies; 2+ messages in thread
From: Mathieu Desnoyers @ 2026-11-08 14:34 UTC (permalink / raw)
To: tglx, mingo, peterz
Cc: linux-kernel, dvhart, dave, andrealmeid, shuah, linux-kselftest
On 2026-11-08 09:23, Mathieu Desnoyers wrote:
> 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.
Self-nack. That's flaky as well. A bounded retry can still fail. This
needs a proper synchronization flag. Will respin a v2.
Thanks,
Mathieu
--
Mathieu Desnoyers
EfficiOS Inc.
https://www.efficios.com
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-11-08 14:34 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-08 14:23 [PATCH] selftests/futex: Retry the wake in futex_wait instead of sleeping Mathieu Desnoyers
2026-11-08 14:34 ` Mathieu Desnoyers
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®