[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:56:01 PDT 2026


https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/192478

>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 1/2] [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);
+}

>From a06f5671783f0772ccb44f7fd0f0c909edf26448 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Thu, 16 Apr 2026 11:55:48 -0400
Subject: [PATCH 2/2] fix

---
 libc/src/__support/threads/CndVar.h             | 2 +-
 libc/src/__support/threads/darwin/futex_utils.h | 3 +--
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/libc/src/__support/threads/CndVar.h b/libc/src/__support/threads/CndVar.h
index f7f0bb6c510af..a423b65bfb0b5 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/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 6ce368a701514..464d78a830b61 100644
--- a/libc/src/__support/threads/darwin/futex_utils.h
+++ b/libc/src/__support/threads/darwin/futex_utils.h
@@ -79,8 +79,7 @@ struct Futex : public cpp::Atomic<FutexWordType> {
 
   LIBC_INLINE ErrorOr<int> requeue_to(Futex & /*other*/,
                                       cpp::optional<FutexWordType> /*oldval*/,
-                                      int /*wake_limit*/,
-                                      int /*requeue_limit*/,
+                                      int /*wake_limit*/, int /*requeue_limit*/,
                                       bool /*is_shared*/ = false) {
     return cpp::unexpected(ENOSYS);
   }



More information about the libc-commits mailing list