[libc-commits] [libc] [libc][threads] adjust futex library and expose requeue API (PR #192478)
Schrodinger ZHU Yifan via libc-commits
libc-commits at lists.llvm.org
Thu Apr 16 08:52:54 PDT 2026
https://github.com/SchrodingerZhu created https://github.com/llvm/llvm-project/pull/192478
None
>From bc88ece7fba815600f8eacea3be20fdf59be046c Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Thu, 16 Apr 2026 11:52:23 -0400
Subject: [PATCH] [libc][threads] adjust futex library and expose requeue API
---
libc/src/__support/threads/CMakeLists.txt | 10 +++-
libc/src/__support/threads/CndVar.h | 2 +-
.../__support/threads/darwin/futex_utils.h | 46 ++++++++++++-------
libc/src/__support/threads/futex_utils.h | 20 ++++++++
.../src/__support/threads/linux/futex_utils.h | 30 ++++++++++++
libc/src/__support/threads/raw_mutex.h | 7 +--
libc/src/semaphore/CMakeLists.txt | 2 +-
libc/src/semaphore/posix_semaphore.h | 2 +-
.../test/src/__support/threads/CMakeLists.txt | 13 ++++++
.../__support/threads/futex_utils_test.cpp | 37 +++++++++++++++
10 files changed, 142 insertions(+), 27 deletions(-)
create mode 100644 libc/src/__support/threads/futex_utils.h
create mode 100644 libc/test/src/__support/threads/futex_utils_test.cpp
diff --git a/libc/src/__support/threads/CMakeLists.txt b/libc/src/__support/threads/CMakeLists.txt
index 9b0b77be098e9..290c27fa46d4f 100644
--- a/libc/src/__support/threads/CMakeLists.txt
+++ b/libc/src/__support/threads/CMakeLists.txt
@@ -24,6 +24,14 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
endif()
if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.futex_utils)
+ add_header_library(
+ futex_utils
+ HDRS
+ futex_utils.h
+ DEPENDS
+ .${LIBC_TARGET_OS}.futex_utils
+ )
+
libc_set_definition(rwlock_default_spin_count "LIBC_COPT_RWLOCK_DEFAULT_SPIN_COUNT=${LIBC_CONF_RWLOCK_DEFAULT_SPIN_COUNT}")
add_header_library(
@@ -33,7 +41,7 @@ if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.futex_utils)
COMPILE_OPTIONS
${monotonicity_flags}
DEPENDS
- .${LIBC_TARGET_OS}.futex_utils
+ .futex_utils
libc.src.__support.threads.sleep
libc.src.__support.time.abs_timeout
libc.src.__support.time.monotonicity
diff --git a/libc/src/__support/threads/CndVar.h b/libc/src/__support/threads/CndVar.h
index 406bcf193704e..f7f0bb6c510af 100644
--- a/libc/src/__support/threads/CndVar.h
+++ b/libc/src/__support/threads/CndVar.h
@@ -11,7 +11,7 @@
#include "hdr/stdint_proxy.h" // uint32_t
#include "src/__support/macros/config.h"
-#include "src/__support/threads/linux/futex_utils.h" // Futex
+#include "src/__support/threads/futex_utils.h" // Futex
#include "src/__support/threads/mutex.h" // Mutex
#include "src/__support/threads/raw_mutex.h" // RawMutex
diff --git a/libc/src/__support/threads/darwin/futex_utils.h b/libc/src/__support/threads/darwin/futex_utils.h
index 65ac1ce0ab351..6ce368a701514 100644
--- a/libc/src/__support/threads/darwin/futex_utils.h
+++ b/libc/src/__support/threads/darwin/futex_utils.h
@@ -11,6 +11,7 @@
#include "src/__support/CPP/atomic.h"
#include "src/__support/CPP/optional.h"
+#include "src/__support/error_or.h"
#include "src/__support/time/abs_timeout.h"
#include "src/__support/time/clock_conversion.h"
#include "src/__support/time/units.h"
@@ -26,11 +27,13 @@ struct Futex : public cpp::Atomic<FutexWordType> {
using Timeout = internal::AbsTimeout;
LIBC_INLINE long wait(FutexWordType val, cpp::optional<Timeout> timeout,
- bool /* is_shared */) {
+ bool is_shared) {
// TODO(bojle): consider using OS_SYNC_WAIT_ON_ADDRESS_SHARED to sync
// betweeen processes. Catch: it is recommended to only be used by shared
// processes, not threads of a same process.
-
+ os_sync_wait_on_address_flags_t flags = OS_SYNC_WAIT_ON_ADDRESS_NONE;
+ if (is_shared)
+ flags = OS_SYNC_WAIT_ON_ADDRESS_SHARED;
for (;;) {
if (this->load(cpp::MemoryOrder::RELAXED) != val)
return 0;
@@ -42,35 +45,44 @@ struct Futex : public cpp::Atomic<FutexWordType> {
timeout->get_timespec().tv_nsec;
ret = os_sync_wait_on_address_with_timeout(
reinterpret_cast<void *>(this), static_cast<uint64_t>(val),
- sizeof(FutexWordType), OS_SYNC_WAIT_ON_ADDRESS_NONE,
- OS_CLOCK_MACH_ABSOLUTE_TIME, tnsec);
+ sizeof(FutexWordType), flags, OS_CLOCK_MACH_ABSOLUTE_TIME, tnsec);
} else {
- ret = os_sync_wait_on_address(
- reinterpret_cast<void *>(this), static_cast<uint64_t>(val),
- sizeof(FutexWordType), OS_SYNC_WAIT_ON_ADDRESS_NONE);
+ ret = os_sync_wait_on_address(reinterpret_cast<void *>(this),
+ static_cast<uint64_t>(val),
+ sizeof(FutexWordType), flags);
}
if ((ret < 0) && (errno == ETIMEDOUT))
return -ETIMEDOUT;
// case when os_sync returns early with an error. retry.
- if ((ret < 0) && ((errno == EINTR) || (errno == EFAULT))) {
+ if ((ret < 0) && ((errno == EINTR) || (errno == EFAULT)))
continue;
- }
return ret;
}
}
- LIBC_INLINE long notify_one(bool /* is_shared */) {
- // TODO(bojle): deal with is_shared
+ LIBC_INLINE long notify_one(bool is_shared) {
+ os_sync_wake_by_address_flags_t flags = OS_SYNC_WAKE_BY_ADDRESS_NONE;
+ if (is_shared)
+ flags = OS_SYNC_WAKE_BY_ADDRESS_SHARED;
+
return os_sync_wake_by_address_any(reinterpret_cast<void *>(this),
- sizeof(FutexWordType),
- OS_SYNC_WAKE_BY_ADDRESS_NONE);
+ sizeof(FutexWordType), flags);
}
- LIBC_INLINE long notify_all(bool /* is_shared */) {
- // TODO(bojle): deal with is_shared
+ LIBC_INLINE long notify_all(bool is_shared) {
+ os_sync_wake_by_address_flags_t flags = OS_SYNC_WAKE_BY_ADDRESS_NONE;
+ if (is_shared)
+ flags = OS_SYNC_WAKE_BY_ADDRESS_SHARED;
return os_sync_wake_by_address_all(reinterpret_cast<void *>(this),
- sizeof(FutexWordType),
- OS_SYNC_WAKE_BY_ADDRESS_NONE);
+ sizeof(FutexWordType), flags);
+ }
+
+ LIBC_INLINE ErrorOr<int> requeue_to(Futex & /*other*/,
+ cpp::optional<FutexWordType> /*oldval*/,
+ int /*wake_limit*/,
+ int /*requeue_limit*/,
+ bool /*is_shared*/ = false) {
+ return cpp::unexpected(ENOSYS);
}
};
diff --git a/libc/src/__support/threads/futex_utils.h b/libc/src/__support/threads/futex_utils.h
new file mode 100644
index 0000000000000..c4393114cbc5b
--- /dev/null
+++ b/libc/src/__support/threads/futex_utils.h
@@ -0,0 +1,20 @@
+//===--- Platform dispatch for futex utilities ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_FUTEX_UTILS_H
+#define LLVM_LIBC_SRC___SUPPORT_THREADS_FUTEX_UTILS_H
+
+#if defined(__linux__)
+#include "src/__support/threads/linux/futex_utils.h"
+#elif defined(__APPLE__)
+#include "src/__support/threads/darwin/futex_utils.h"
+#else
+#error "futex_utils is not supported on this platform"
+#endif
+
+#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_FUTEX_UTILS_H
diff --git a/libc/src/__support/threads/linux/futex_utils.h b/libc/src/__support/threads/linux/futex_utils.h
index e1cfa36566555..84cdc06ce2076 100644
--- a/libc/src/__support/threads/linux/futex_utils.h
+++ b/libc/src/__support/threads/linux/futex_utils.h
@@ -13,6 +13,7 @@
#include "src/__support/CPP/limits.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/OSUtil/syscall.h"
+#include "src/__support/error_or.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
#include "src/__support/threads/linux/futex_word.h"
@@ -79,6 +80,35 @@ class Futex : public cpp::Atomic<FutexWordType> {
/* ignored */ nullptr,
/* ignored */ 0);
}
+ LIBC_INLINE ErrorOr<int> requeue_to(Futex &other,
+ cpp::optional<FutexWordType> oldval,
+ int wake_limit, int requeue_limit,
+ bool is_shared = false) {
+ int ret;
+ if (oldval)
+ ret = syscall_impl<int>(
+ /* syscall number */ FUTEX_SYSCALL_ID,
+ /* futex address */ this,
+ /* futex operation */
+ is_shared ? FUTEX_CMP_REQUEUE : FUTEX_CMP_REQUEUE_PRIVATE,
+ /* wake up limit */ wake_limit,
+ /* requeue limit */ requeue_limit,
+ /* requeue address */ &other, *oldval);
+ else
+ ret = syscall_impl<int>(
+ /* syscall number */ FUTEX_SYSCALL_ID,
+ /* futex address */ this,
+ /* futex operation */
+ is_shared ? FUTEX_REQUEUE : FUTEX_REQUEUE_PRIVATE,
+ /* wake up limit */ wake_limit,
+ /* requeue limit */
+ requeue_limit,
+ /* requeue address */
+ &other);
+ if (ret < 0)
+ return cpp::unexpected<int>(-ret);
+ return static_cast<int>(ret);
+ }
};
static_assert(__is_standard_layout(Futex),
diff --git a/libc/src/__support/threads/raw_mutex.h b/libc/src/__support/threads/raw_mutex.h
index e68469ad531cc..aa0a8612e79de 100644
--- a/libc/src/__support/threads/raw_mutex.h
+++ b/libc/src/__support/threads/raw_mutex.h
@@ -15,17 +15,12 @@
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/optimization.h"
+#include "src/__support/threads/futex_utils.h"
#include "src/__support/threads/sleep.h"
#include "src/__support/time/abs_timeout.h"
#include <stdio.h>
-#if defined(__linux__)
-#include "src/__support/threads/linux/futex_utils.h"
-#elif defined(__APPLE__)
-#include "src/__support/threads/darwin/futex_utils.h"
-#endif
-
#ifndef LIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY
#define LIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY 1
#endif
diff --git a/libc/src/semaphore/CMakeLists.txt b/libc/src/semaphore/CMakeLists.txt
index ac73eb8e87b56..45da6f1af7966 100644
--- a/libc/src/semaphore/CMakeLists.txt
+++ b/libc/src/semaphore/CMakeLists.txt
@@ -4,5 +4,5 @@ add_header_library(
posix_semaphore.h
DEPENDS
libc.src.__support.CPP.atomic
- libc.src.__support.threads.linux.futex_utils
+ libc.src.__support.threads.futex_utils
)
diff --git a/libc/src/semaphore/posix_semaphore.h b/libc/src/semaphore/posix_semaphore.h
index 7b14d41165a96..11adfb5a209c4 100644
--- a/libc/src/semaphore/posix_semaphore.h
+++ b/libc/src/semaphore/posix_semaphore.h
@@ -11,7 +11,7 @@
#include "src/__support/CPP/atomic.h"
#include "src/__support/common.h"
-#include "src/__support/threads/linux/futex_utils.h"
+#include "src/__support/threads/futex_utils.h"
namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/test/src/__support/threads/CMakeLists.txt b/libc/test/src/__support/threads/CMakeLists.txt
index 70d68abba6e30..deb05689f8f9a 100644
--- a/libc/test/src/__support/threads/CMakeLists.txt
+++ b/libc/test/src/__support/threads/CMakeLists.txt
@@ -1,4 +1,17 @@
add_custom_target(libc-support-threads-tests)
+
+if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.futex_utils)
+ add_libc_test(
+ futex_utils_test
+ SUITE
+ libc-support-threads-tests
+ SRCS
+ futex_utils_test.cpp
+ DEPENDS
+ libc.src.__support.threads.futex_utils
+ )
+endif()
+
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
add_subdirectory(${LIBC_TARGET_OS})
endif()
diff --git a/libc/test/src/__support/threads/futex_utils_test.cpp b/libc/test/src/__support/threads/futex_utils_test.cpp
new file mode 100644
index 0000000000000..451b79ec28a7e
--- /dev/null
+++ b/libc/test/src/__support/threads/futex_utils_test.cpp
@@ -0,0 +1,37 @@
+//===-- Unittests for futex utilities ------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/CPP/optional.h"
+#include "src/__support/threads/futex_utils.h"
+#include "test/UnitTest/Test.h"
+
+#include <errno.h>
+
+TEST(LlvmLibcSupportThreadsFutexUtilsTest, RequeueSmokeTest) {
+ LIBC_NAMESPACE::Futex source(1);
+ LIBC_NAMESPACE::Futex destination(2);
+
+ auto no_requeue = source.requeue_to(destination, 1, 1, 0);
+ if (no_requeue.has_value())
+ ASSERT_EQ(*no_requeue, 0);
+ else
+ ASSERT_EQ(no_requeue.error(), ENOSYS);
+
+ auto no_wake = source.requeue_to(destination, 1, 0, 1);
+ if (no_wake.has_value())
+ ASSERT_EQ(*no_wake, 0);
+ else
+ ASSERT_EQ(no_wake.error(), ENOSYS);
+
+ auto cmp_mismatch = source.requeue_to(destination, 0, 0, 1);
+ if (cmp_mismatch.has_value())
+ ASSERT_EQ(*cmp_mismatch, 0);
+ else
+ ASSERT_TRUE(cmp_mismatch.error() == ENOSYS ||
+ cmp_mismatch.error() == EAGAIN);
+}
More information about the libc-commits
mailing list