[libc-commits] [libc] [libc] Add Darwin mutex support via os_sync primitives (PR #167722)
Shreeyash Pandey via libc-commits
libc-commits at lists.llvm.org
Mon Dec 8 08:58:31 PST 2025
https://github.com/bojle updated https://github.com/llvm/llvm-project/pull/167722
>From 8e971b78d7fa17d688abc229a730b85b0f5d8837 Mon Sep 17 00:00:00 2001
From: Shreeyash Pandey <shreeyash335 at gmail.com>
Date: Wed, 12 Nov 2025 21:16:22 +0530
Subject: [PATCH 1/8] [libc] Add Darwin mutex support via os_sync primitives
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This patch implements the generic mutex and raw_mutex interfaces on macOS.
A new Futex class is provided that relies on os_sync_wait and
os_sync_wake to emulate futex‑like wait and wake semantics.
The OS‑specific part is moved into futex_utils, which now contains the
Darwin implementation.
---
libc/src/__support/threads/CMakeLists.txt | 29 +++-
.../__support/threads/darwin/CMakeLists.txt | 16 +++
.../__support/threads/darwin/futex_utils.h | 66 +++++++++
libc/src/__support/threads/darwin/mutex.h | 131 ++++++++++++++++++
libc/src/__support/threads/mutex.h | 6 +
.../__support/threads/{linux => }/raw_mutex.h | 24 ++--
.../threads/{linux/mutex.h => unix_mutex.h} | 9 +-
7 files changed, 265 insertions(+), 16 deletions(-)
create mode 100644 libc/src/__support/threads/darwin/CMakeLists.txt
create mode 100644 libc/src/__support/threads/darwin/futex_utils.h
create mode 100644 libc/src/__support/threads/darwin/mutex.h
rename libc/src/__support/threads/{linux => }/raw_mutex.h (89%)
rename libc/src/__support/threads/{linux/mutex.h => unix_mutex.h} (90%)
diff --git a/libc/src/__support/threads/CMakeLists.txt b/libc/src/__support/threads/CMakeLists.txt
index f8a44937721b4..b2abf19c53a50 100644
--- a/libc/src/__support/threads/CMakeLists.txt
+++ b/libc/src/__support/threads/CMakeLists.txt
@@ -23,13 +23,36 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
add_subdirectory(${LIBC_TARGET_OS})
endif()
-if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.mutex)
+if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.futex_utils)
add_header_library(
mutex
HDRS
- mutex.h
+ mutex.h
+ DEPENDS
+ .unix_mutex
+ )
+ add_header_library(
+ unix_mutex
+ HDRS
+ unix_mutex.h
+ DEPENDS
+ .raw_mutex
+ )
+
+ add_header_library(
+ raw_mutex
+ HDRS
+ raw_mutex.h
DEPENDS
- .${LIBC_TARGET_OS}.mutex
+ .${LIBC_TARGET_OS}.futex_utils
+ libc.src.__support.threads.sleep
+ libc.src.__support.time.abs_timeout
+ libc.src.__support.time.monotonicity
+ libc.src.__support.CPP.optional
+ libc.hdr.types.pid_t
+ COMPILE_OPTIONS
+ -DLIBC_COPT_RAW_MUTEX_DEFAULT_SPIN_COUNT=${LIBC_CONF_RAW_MUTEX_DEFAULT_SPIN_COUNT}
+ ${monotonicity_flags}
)
add_object_library(
diff --git a/libc/src/__support/threads/darwin/CMakeLists.txt b/libc/src/__support/threads/darwin/CMakeLists.txt
new file mode 100644
index 0000000000000..9c651d8c3b0f5
--- /dev/null
+++ b/libc/src/__support/threads/darwin/CMakeLists.txt
@@ -0,0 +1,16 @@
+if(NOT TARGET libc.src.__support.OSUtil.osutil)
+ return()
+endif()
+
+add_header_library(
+ futex_utils
+ HDRS
+ futex_utils.h
+ DEPENDS
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.CPP.atomic
+ libc.src.__support.CPP.limits
+ libc.src.__support.CPP.optional
+ libc.src.__support.threads.mutex_common
+)
diff --git a/libc/src/__support/threads/darwin/futex_utils.h b/libc/src/__support/threads/darwin/futex_utils.h
new file mode 100644
index 0000000000000..180083b7b2c68
--- /dev/null
+++ b/libc/src/__support/threads/darwin/futex_utils.h
@@ -0,0 +1,66 @@
+//===--- Futex utils for Darwin -----------------------------------*- 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_DARWIN_FUTEX_UTILS_H
+#define LLVM_LIBC_SRC___SUPPORT_THREADS_DARWIN_FUTEX_UTILS_H
+
+#include "src/__support/CPP/atomic.h"
+#include "src/__support/CPP/optional.h"
+#include "src/__support/time/abs_timeout.h"
+#include "src/__support/time/clock_conversion.h"
+
+#include <os/os_sync_wait_on_address.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+using FutexWordType = uint32_t;
+
+struct Futex : public cpp::Atomic<FutexWordType> {
+ using cpp::Atomic<FutexWordType>::Atomic;
+ using Timeout = internal::AbsTimeout;
+
+ // The Darwin futex API does not return a value on timeout, so we have to
+ // check for it manually. This means we can't use the return value to
+ // distinguish between a timeout and a successful wake-up.
+ int wait(FutexWordType val, cpp::optional<Timeout> timeout, bool) {
+ if (timeout) {
+ struct timespec now;
+ clock_gettime(timeout->is_realtime() ? CLOCK_REALTIME : CLOCK_MONOTONIC,
+ &now);
+ const timespec &target_ts = timeout->get_timespec();
+
+ if (now.tv_sec > target_ts.tv_sec ||
+ (now.tv_sec == target_ts.tv_sec && now.tv_nsec >= target_ts.tv_nsec))
+ return ETIMEDOUT;
+ }
+
+ os_sync_wait_on_address(reinterpret_cast<void *>(this),
+ static_cast<uint64_t>(val), sizeof(FutexWordType),
+ OS_SYNC_WAIT_ON_ADDRESS_NONE);
+ return 0;
+ }
+
+ void notify_one(bool) {
+ os_sync_wake_by_address_any(reinterpret_cast<void *>(this),
+ sizeof(FutexWordType),
+ OS_SYNC_WAKE_BY_ADDRESS_NONE);
+ }
+
+ void notify_all(bool) {
+ // os_sync_wake_by_address_all is not available, so we use notify_one.
+ // This is not ideal, but it's the best we can do with the available API.
+ os_sync_wake_by_address_any(reinterpret_cast<void *>(this),
+ sizeof(FutexWordType),
+ OS_SYNC_WAKE_BY_ADDRESS_NONE);
+ }
+};
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_DARWIN_FUTEX_UTILS_H
diff --git a/libc/src/__support/threads/darwin/mutex.h b/libc/src/__support/threads/darwin/mutex.h
new file mode 100644
index 0000000000000..44ba14cc986a2
--- /dev/null
+++ b/libc/src/__support/threads/darwin/mutex.h
@@ -0,0 +1,131 @@
+//===--- Implementation of a Darwin mutex class -----------*- 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_DARWIN_MUTEX_H
+#define LLVM_LIBC_SRC___SUPPORT_THREADS_DARWIN_MUTEX_H
+
+#include "src/__support/libc_assert.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/threads/mutex_common.h"
+#include "src/__support/threads/sleep.h" // For sleep_briefly
+#include "src/__support/time/abs_timeout.h"
+
+#include <mach/mach_init.h> // For mach_thread_self
+#include <mach/mach_port.h> // For mach_port_t and MACH_PORT_NULL
+#include <os/lock.h> // For os_unfair_lock
+#include <time.h> // For clock_gettime
+
+namespace LIBC_NAMESPACE_DECL {
+
+// This file is an implementation of `LIBC_NAMESPACE::mutex` for Darwin-based
+// platforms. It is a wrapper around `os_unfair_lock`, which is a low-level,
+// high-performance locking primitive provided by the kernel.
+//
+// `os_unfair_lock` is a non-recursive, thread-owned lock that blocks waiters
+// efficiently in the kernel. As the name implies, it is "unfair," meaning
+// it does not guarantee the order in which waiting threads acquire the lock.
+// This trade-off allows for higher performance in contended scenarios.
+//
+// The lock must be unlocked from the same thread that locked it. Attempting
+// to unlock from a different thread will result in a runtime error.
+//
+// This implementation is suitable for simple critical sections where fairness
+// and reentrancy are not concerns.
+
+class Mutex final {
+ os_unfair_lock_s lock_val = OS_UNFAIR_LOCK_INIT;
+ mach_port_t owner = MACH_PORT_NULL;
+
+ // API compatibility fields.
+ unsigned char timed;
+ unsigned char recursive;
+ unsigned char robust;
+ unsigned char pshared;
+
+public:
+ LIBC_INLINE constexpr Mutex(bool is_timed, bool is_recursive, bool is_robust,
+ bool is_pshared)
+ : owner(MACH_PORT_NULL), timed(is_timed), recursive(is_recursive),
+ robust(is_robust), pshared(is_pshared) {}
+
+ LIBC_INLINE constexpr Mutex()
+ : owner(MACH_PORT_NULL), timed(0), recursive(0), robust(0), pshared(0) {}
+
+ LIBC_INLINE static MutexError init(Mutex *mutex, bool is_timed, bool is_recur,
+ bool is_robust, bool is_pshared) {
+ mutex->lock_val = OS_UNFAIR_LOCK_INIT;
+ mutex->owner = MACH_PORT_NULL;
+ mutex->timed = is_timed;
+ mutex->recursive = is_recur;
+ mutex->robust = is_robust;
+ mutex->pshared = is_pshared;
+ return MutexError::NONE;
+ }
+
+ LIBC_INLINE static MutexError destroy(Mutex *lock) {
+ LIBC_ASSERT(lock->owner == MACH_PORT_NULL &&
+ "Mutex destroyed while locked.");
+ return MutexError::NONE;
+ }
+
+ LIBC_INLINE MutexError lock() {
+ os_unfair_lock_lock(&lock_val);
+ owner = mach_thread_self();
+ return MutexError::NONE;
+ }
+
+ LIBC_INLINE MutexError timed_lock(internal::AbsTimeout abs_time) {
+ while (true) {
+ if (try_lock() == MutexError::NONE) {
+ return MutexError::NONE;
+ }
+
+ // Manually check if the timeout has expired.
+ struct timespec now;
+ // The clock used here must match the clock used to create the
+ // absolute timeout.
+ clock_gettime(abs_time.is_realtime() ? CLOCK_REALTIME : CLOCK_MONOTONIC,
+ &now);
+ const timespec &target_ts = abs_time.get_timespec();
+
+ if (now.tv_sec > target_ts.tv_sec || (now.tv_sec == target_ts.tv_sec &&
+ now.tv_nsec >= target_ts.tv_nsec)) {
+ // We might have acquired the lock between the last try_lock() and now.
+ // To avoid returning TIMEOUT incorrectly, we do one last try_lock().
+ if (try_lock() == MutexError::NONE)
+ return MutexError::NONE;
+ return MutexError::TIMEOUT;
+ }
+
+ sleep_briefly();
+ }
+ }
+
+ LIBC_INLINE MutexError unlock() {
+ // This check is crucial. It prevents both double-unlocks and unlocks
+ // by threads that do not own the mutex.
+ if (owner != mach_thread_self()) {
+ return MutexError::UNLOCK_WITHOUT_LOCK;
+ }
+ owner = MACH_PORT_NULL;
+ os_unfair_lock_unlock(&lock_val);
+ return MutexError::NONE;
+ }
+
+ LIBC_INLINE MutexError try_lock() {
+ if (os_unfair_lock_trylock(&lock_val)) {
+ owner = mach_thread_self();
+ return MutexError::NONE;
+ }
+ return MutexError::BUSY;
+ }
+};
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_DARWIN_MUTEX_H
diff --git a/libc/src/__support/threads/mutex.h b/libc/src/__support/threads/mutex.h
index f64f7e7b40082..2ebbf39873818 100644
--- a/libc/src/__support/threads/mutex.h
+++ b/libc/src/__support/threads/mutex.h
@@ -40,9 +40,15 @@
// few global locks. So, to avoid static initialization order fiasco, we
// want the constructors of the Mutex classes to be constexprs.
+<<<<<<< HEAD
#if defined(__linux__)
#include "src/__support/threads/linux/mutex.h"
#endif // __linux__
+=======
+#if defined(__linux__) || defined(__APPLE__)
+#include "src/__support/threads/unix_mutex.h"
+#endif
+>>>>>>> c35b95c04bf7 ([libc] Add Darwin mutex support via os_sync primitives)
#elif LIBC_THREAD_MODE == LIBC_THREAD_MODE_SINGLE
diff --git a/libc/src/__support/threads/linux/raw_mutex.h b/libc/src/__support/threads/raw_mutex.h
similarity index 89%
rename from libc/src/__support/threads/linux/raw_mutex.h
rename to libc/src/__support/threads/raw_mutex.h
index 94d6129bbf69b..fb3f5c0f70ed6 100644
--- a/libc/src/__support/threads/linux/raw_mutex.h
+++ b/libc/src/__support/threads/raw_mutex.h
@@ -1,12 +1,12 @@
-//===--- Implementation of a Linux RawMutex class ---------------*- C++ -*-===//
+//===--- Implementation of the RawMutex class ---------------*- 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_LINUX_RAW_MUTEX_H
-#define LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_RAW_MUTEX_H
+//===------------------------------------------------------------------===//
+#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_RAW_MUTEX_H
+#define LLVM_LIBC_SRC___SUPPORT_THREADS_RAW_MUTEX_H
#include "src/__support/CPP/optional.h"
#include "src/__support/common.h"
@@ -14,15 +14,21 @@
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/optimization.h"
-#include "src/__support/threads/linux/futex_utils.h"
-#include "src/__support/threads/linux/futex_word.h"
#include "src/__support/threads/sleep.h"
#include "src/__support/time/abs_timeout.h"
+#include "sys/errno.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
+// TODO(bojle): check this for darwin impl
#if LIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY
#include "src/__support/time/monotonicity.h"
#endif
@@ -93,7 +99,9 @@ class RawMutex {
LIBC_INLINE void wake(bool is_pshared) { futex.notify_one(is_pshared); }
public:
- LIBC_INLINE static void init(RawMutex *mutex) { mutex->futex = UNLOCKED; }
+ LIBC_INLINE static void init(RawMutex *mutex) {
+ mutex->futex.store(UNLOCKED);
+ }
LIBC_INLINE constexpr RawMutex() : futex(UNLOCKED) {}
[[nodiscard]] LIBC_INLINE bool try_lock() {
FutexWordType expected = UNLOCKED;
@@ -122,7 +130,7 @@ class RawMutex {
LIBC_ASSERT(lock->futex == UNLOCKED && "Mutex destroyed while used.");
}
LIBC_INLINE Futex &get_raw_futex() { return futex; }
- LIBC_INLINE void reset() { futex = UNLOCKED; }
+ LIBC_INLINE void reset() { futex.store(UNLOCKED); }
};
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/__support/threads/linux/mutex.h b/libc/src/__support/threads/unix_mutex.h
similarity index 90%
rename from libc/src/__support/threads/linux/mutex.h
rename to libc/src/__support/threads/unix_mutex.h
index 0c4b1ae09af6f..31acd582d4c6c 100644
--- a/libc/src/__support/threads/linux/mutex.h
+++ b/libc/src/__support/threads/unix_mutex.h
@@ -1,4 +1,4 @@
-//===--- Implementation of a Linux mutex class ------------------*- C++ -*-===//
+//===--- Implementation of a Unix mutex class ------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -6,16 +6,15 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_MUTEX_H
-#define LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_MUTEX_H
+#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_UNIX_MUTEX_H
+#define LLVM_LIBC_SRC___SUPPORT_THREADS_UNIX_MUTEX_H
#include "hdr/types/pid_t.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/libc_assert.h"
#include "src/__support/macros/config.h"
-#include "src/__support/threads/linux/futex_utils.h"
-#include "src/__support/threads/linux/raw_mutex.h"
#include "src/__support/threads/mutex_common.h"
+#include "src/__support/threads/raw_mutex.h"
namespace LIBC_NAMESPACE_DECL {
>From 23ff0b8a7619ef8674c1f6309d8563deee84c171 Mon Sep 17 00:00:00 2001
From: Shreeyash Pandey <shreeyash335 at gmail.com>
Date: Fri, 28 Nov 2025 23:19:18 +0530
Subject: [PATCH 2/8] [libc][darwin] use os_sync_*_timeouts and clear tests
---
.../__support/threads/darwin/futex_utils.h | 72 +++++++++++--------
libc/src/__support/threads/raw_mutex.h | 2 +
.../__support/threads/darwin/mutex_test.cpp | 45 ++++++++++++
3 files changed, 89 insertions(+), 30 deletions(-)
create mode 100644 libc/test/src/__support/threads/darwin/mutex_test.cpp
diff --git a/libc/src/__support/threads/darwin/futex_utils.h b/libc/src/__support/threads/darwin/futex_utils.h
index 180083b7b2c68..380be69b2a66a 100644
--- a/libc/src/__support/threads/darwin/futex_utils.h
+++ b/libc/src/__support/threads/darwin/futex_utils.h
@@ -1,11 +1,10 @@
-//===--- Futex utils for Darwin -----------------------------------*- C++
-//-*-===//
+//===--- Futex utils for Darwin ------------------------*- 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_DARWIN_FUTEX_UTILS_H
#define LLVM_LIBC_SRC___SUPPORT_THREADS_DARWIN_FUTEX_UTILS_H
@@ -25,39 +24,52 @@ struct Futex : public cpp::Atomic<FutexWordType> {
using cpp::Atomic<FutexWordType>::Atomic;
using Timeout = internal::AbsTimeout;
- // The Darwin futex API does not return a value on timeout, so we have to
- // check for it manually. This means we can't use the return value to
- // distinguish between a timeout and a successful wake-up.
- int wait(FutexWordType val, cpp::optional<Timeout> timeout, bool) {
- if (timeout) {
- struct timespec now;
- clock_gettime(timeout->is_realtime() ? CLOCK_REALTIME : CLOCK_MONOTONIC,
- &now);
- const timespec &target_ts = timeout->get_timespec();
+ LIBC_INLINE long wait(FutexWordType val, cpp::optional<Timeout> timeout,
+ 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.
- if (now.tv_sec > target_ts.tv_sec ||
- (now.tv_sec == target_ts.tv_sec && now.tv_nsec >= target_ts.tv_nsec))
- return ETIMEDOUT;
+ for (;;) {
+ if (this->load(cpp::MemoryOrder::RELAXED) != val)
+ return 0;
+ long ret = 0;
+ if (timeout) {
+ // Assuming, OS_CLOCK_MACH_ABSOLUTE_TIME is equivalent to CLOCK_REALTIME
+ uint64_t tnsec = timeout->get_timespec().tv_sec * 1000000000 +
+ 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);
+ } else {
+ ret = os_sync_wait_on_address(
+ reinterpret_cast<void *>(this), static_cast<uint64_t>(val),
+ sizeof(FutexWordType), OS_SYNC_WAIT_ON_ADDRESS_NONE);
+ }
+ if ((ret < 0) && (errno == ETIMEDOUT)) {
+ return -ETIMEDOUT;
+ }
+ // case when os_sync returns early with an error. retry.
+ if ((ret < 0) && ((errno == EINTR) || (errno == EFAULT))) {
+ continue;
+ }
+ return ret;
}
-
- os_sync_wait_on_address(reinterpret_cast<void *>(this),
- static_cast<uint64_t>(val), sizeof(FutexWordType),
- OS_SYNC_WAIT_ON_ADDRESS_NONE);
- return 0;
}
- void notify_one(bool) {
- os_sync_wake_by_address_any(reinterpret_cast<void *>(this),
- sizeof(FutexWordType),
- OS_SYNC_WAKE_BY_ADDRESS_NONE);
+ LIBC_INLINE long notify_one(bool /* is_shared */) {
+ // TODO(bojle): deal with is_shared
+ return os_sync_wake_by_address_any(reinterpret_cast<void *>(this),
+ sizeof(FutexWordType),
+ OS_SYNC_WAKE_BY_ADDRESS_NONE);
}
- void notify_all(bool) {
- // os_sync_wake_by_address_all is not available, so we use notify_one.
- // This is not ideal, but it's the best we can do with the available API.
- os_sync_wake_by_address_any(reinterpret_cast<void *>(this),
- sizeof(FutexWordType),
- OS_SYNC_WAKE_BY_ADDRESS_NONE);
+ LIBC_INLINE long notify_all(bool /* is_shared */) {
+ // TODO(bojle): deal with is_shared
+ return os_sync_wake_by_address_all(reinterpret_cast<void *>(this),
+ sizeof(FutexWordType),
+ OS_SYNC_WAKE_BY_ADDRESS_NONE);
}
};
diff --git a/libc/src/__support/threads/raw_mutex.h b/libc/src/__support/threads/raw_mutex.h
index fb3f5c0f70ed6..c8f35a5785fd7 100644
--- a/libc/src/__support/threads/raw_mutex.h
+++ b/libc/src/__support/threads/raw_mutex.h
@@ -18,6 +18,8 @@
#include "src/__support/time/abs_timeout.h"
#include "sys/errno.h"
+#include <stdio.h>
+
#if defined(__linux__)
#include "src/__support/threads/linux/futex_utils.h"
#elif defined(__APPLE__)
diff --git a/libc/test/src/__support/threads/darwin/mutex_test.cpp b/libc/test/src/__support/threads/darwin/mutex_test.cpp
new file mode 100644
index 0000000000000..b87da8670e422
--- /dev/null
+++ b/libc/test/src/__support/threads/darwin/mutex_test.cpp
@@ -0,0 +1,45 @@
+//===-- Unittests for Darwin's Mutex ------------------------------------===//
+//
+// 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/threads/mutex.h"
+#include "src/__support/threads/mutex_common.h"
+#include "src/__support/threads/raw_mutex.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcSupportThreadsMutexTest, SmokeTest) {
+ LIBC_NAMESPACE::Mutex mutex(0, 0, 0, 0);
+ ASSERT_EQ(mutex.lock(), LIBC_NAMESPACE::MutexError::NONE);
+ ASSERT_EQ(mutex.unlock(), LIBC_NAMESPACE::MutexError::NONE);
+ ASSERT_EQ(mutex.try_lock(), LIBC_NAMESPACE::MutexError::NONE);
+ ASSERT_EQ(mutex.try_lock(), LIBC_NAMESPACE::MutexError::BUSY);
+ ASSERT_EQ(mutex.unlock(), LIBC_NAMESPACE::MutexError::NONE);
+ ASSERT_EQ(mutex.unlock(), LIBC_NAMESPACE::MutexError::UNLOCK_WITHOUT_LOCK);
+}
+
+TEST(LlvmLibcSupportThreadsRawMutexTest, Timeout) {
+ LIBC_NAMESPACE::RawMutex mutex;
+ ASSERT_TRUE(mutex.lock());
+ timespec ts;
+ LIBC_NAMESPACE::internal::clock_gettime(CLOCK_MONOTONIC, &ts);
+ ts.tv_sec += 1;
+ // Timeout will be respected when deadlock happens.
+ auto timeout = LIBC_NAMESPACE::internal::AbsTimeout::from_timespec(ts, false);
+ ASSERT_TRUE(timeout.has_value());
+ // The following will timeout
+ ASSERT_FALSE(mutex.lock(*timeout));
+ ASSERT_TRUE(mutex.unlock());
+ // Test that the mutex works after the timeout.
+ ASSERT_TRUE(mutex.lock());
+ ASSERT_TRUE(mutex.unlock());
+ // If a lock can be acquired directly, expired timeout will not count.
+ // Notice that the timeout is already reached during preivous deadlock.
+ ASSERT_TRUE(mutex.lock(*timeout));
+ ASSERT_TRUE(mutex.unlock());
+}
+
+// TODO(bojle): add other tests a la linux
>From 031c00a3c657d6f7273d16238a62a4602f6c869f Mon Sep 17 00:00:00 2001
From: Shreeyash Pandey <shreeyash335 at gmail.com>
Date: Wed, 3 Dec 2025 18:50:33 +0530
Subject: [PATCH 3/8] [libc][darwin] clean rebase conflict remnants
---
libc/src/__support/threads/mutex.h | 6 ------
1 file changed, 6 deletions(-)
diff --git a/libc/src/__support/threads/mutex.h b/libc/src/__support/threads/mutex.h
index 2ebbf39873818..25feea891e429 100644
--- a/libc/src/__support/threads/mutex.h
+++ b/libc/src/__support/threads/mutex.h
@@ -40,15 +40,9 @@
// few global locks. So, to avoid static initialization order fiasco, we
// want the constructors of the Mutex classes to be constexprs.
-<<<<<<< HEAD
-#if defined(__linux__)
-#include "src/__support/threads/linux/mutex.h"
-#endif // __linux__
-=======
#if defined(__linux__) || defined(__APPLE__)
#include "src/__support/threads/unix_mutex.h"
#endif
->>>>>>> c35b95c04bf7 ([libc] Add Darwin mutex support via os_sync primitives)
#elif LIBC_THREAD_MODE == LIBC_THREAD_MODE_SINGLE
>From 78c191a65c072fcff7ad578b7889d25d61ea0d00 Mon Sep 17 00:00:00 2001
From: Shreeyash Pandey <shreeyash335 at gmail.com>
Date: Wed, 3 Dec 2025 19:16:31 +0530
Subject: [PATCH 4/8] [libc][darwin] cmake options, minor nits
---
.../modules/LLVMLibCCompileOptionRules.cmake | 4 +
libc/src/__support/threads/CMakeLists.txt | 44 +++---
.../__support/threads/darwin/futex_utils.h | 7 +-
libc/src/__support/threads/darwin/mutex.h | 131 ------------------
4 files changed, 29 insertions(+), 157 deletions(-)
delete mode 100644 libc/src/__support/threads/darwin/mutex.h
diff --git a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
index 619b53f828705..5caf840a4cfeb 100644
--- a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
+++ b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
@@ -119,6 +119,10 @@ function(_get_compile_options_from_config output_var)
list(APPEND config_options "-DLIBC_TRAP_ON_RAISE_FP_EXCEPT")
endif()
+ if(LIBC_CONF_RAW_MUTEX_DEFAULT_SPIN_COUNT)
+ list(APPEND config_options "-DLIBC_COPT_RAW_MUTEX_DEFAULT_SPIN_COUNT=${LIBC_CONF_RAW_MUTEX_DEFAULT_SPIN_COUNT}")
+ endif()
+
set(${output_var} ${config_options} PARENT_SCOPE)
endfunction(_get_compile_options_from_config)
diff --git a/libc/src/__support/threads/CMakeLists.txt b/libc/src/__support/threads/CMakeLists.txt
index b2abf19c53a50..dc1445634da2b 100644
--- a/libc/src/__support/threads/CMakeLists.txt
+++ b/libc/src/__support/threads/CMakeLists.txt
@@ -25,52 +25,52 @@ endif()
if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.futex_utils)
add_header_library(
- mutex
+ raw_mutex
HDRS
- mutex.h
+ raw_mutex.h
+ COMPILE_OPTIONS
+ ${monotonicity_flags}
DEPENDS
- .unix_mutex
+ .${LIBC_TARGET_OS}.futex_utils
+ libc.src.__support.threads.sleep
+ libc.src.__support.time.abs_timeout
+ libc.src.__support.time.monotonicity
+ libc.src.__support.CPP.optional
+ libc.hdr.types.pid_t
)
+
add_header_library(
unix_mutex
HDRS
- unix_mutex.h
+ unix_mutex.h
DEPENDS
- .raw_mutex
+ .raw_mutex
)
add_header_library(
- raw_mutex
+ mutex
HDRS
- raw_mutex.h
+ mutex.h
DEPENDS
- .${LIBC_TARGET_OS}.futex_utils
- libc.src.__support.threads.sleep
- libc.src.__support.time.abs_timeout
- libc.src.__support.time.monotonicity
- libc.src.__support.CPP.optional
- libc.hdr.types.pid_t
- COMPILE_OPTIONS
- -DLIBC_COPT_RAW_MUTEX_DEFAULT_SPIN_COUNT=${LIBC_CONF_RAW_MUTEX_DEFAULT_SPIN_COUNT}
- ${monotonicity_flags}
+ .unix_mutex
)
add_object_library(
fork_callbacks
SRCS
- fork_callbacks.cpp
+ fork_callbacks.cpp
HDRS
- fork_callbacks.h
+ fork_callbacks.h
DEPENDS
- .mutex
- libc.src.__support.CPP.mutex
+ .mutex
+ libc.src.__support.CPP.mutex
)
elseif(NOT (LIBC_CONF_THREAD_MODE STREQUAL LIBC_THREAD_MODE_PLATFORM))
add_header_library(
mutex
- HDRS
+ HDRS
mutex.h
- DEPENDS
+ DEPENDS
.mutex_common
)
endif()
diff --git a/libc/src/__support/threads/darwin/futex_utils.h b/libc/src/__support/threads/darwin/futex_utils.h
index 380be69b2a66a..f880d09f621fc 100644
--- a/libc/src/__support/threads/darwin/futex_utils.h
+++ b/libc/src/__support/threads/darwin/futex_utils.h
@@ -1,10 +1,10 @@
-//===--- Futex utils for Darwin ------------------------*- C++-*-===//
+//===--- Futex utils for Darwin ----------------------------------*- 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_DARWIN_FUTEX_UTILS_H
#define LLVM_LIBC_SRC___SUPPORT_THREADS_DARWIN_FUTEX_UTILS_H
@@ -47,9 +47,8 @@ struct Futex : public cpp::Atomic<FutexWordType> {
reinterpret_cast<void *>(this), static_cast<uint64_t>(val),
sizeof(FutexWordType), OS_SYNC_WAIT_ON_ADDRESS_NONE);
}
- if ((ret < 0) && (errno == ETIMEDOUT)) {
+ if ((ret < 0) && (errno == ETIMEDOUT))
return -ETIMEDOUT;
- }
// case when os_sync returns early with an error. retry.
if ((ret < 0) && ((errno == EINTR) || (errno == EFAULT))) {
continue;
diff --git a/libc/src/__support/threads/darwin/mutex.h b/libc/src/__support/threads/darwin/mutex.h
deleted file mode 100644
index 44ba14cc986a2..0000000000000
--- a/libc/src/__support/threads/darwin/mutex.h
+++ /dev/null
@@ -1,131 +0,0 @@
-//===--- Implementation of a Darwin mutex class -----------*- 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_DARWIN_MUTEX_H
-#define LLVM_LIBC_SRC___SUPPORT_THREADS_DARWIN_MUTEX_H
-
-#include "src/__support/libc_assert.h"
-#include "src/__support/macros/config.h"
-#include "src/__support/threads/mutex_common.h"
-#include "src/__support/threads/sleep.h" // For sleep_briefly
-#include "src/__support/time/abs_timeout.h"
-
-#include <mach/mach_init.h> // For mach_thread_self
-#include <mach/mach_port.h> // For mach_port_t and MACH_PORT_NULL
-#include <os/lock.h> // For os_unfair_lock
-#include <time.h> // For clock_gettime
-
-namespace LIBC_NAMESPACE_DECL {
-
-// This file is an implementation of `LIBC_NAMESPACE::mutex` for Darwin-based
-// platforms. It is a wrapper around `os_unfair_lock`, which is a low-level,
-// high-performance locking primitive provided by the kernel.
-//
-// `os_unfair_lock` is a non-recursive, thread-owned lock that blocks waiters
-// efficiently in the kernel. As the name implies, it is "unfair," meaning
-// it does not guarantee the order in which waiting threads acquire the lock.
-// This trade-off allows for higher performance in contended scenarios.
-//
-// The lock must be unlocked from the same thread that locked it. Attempting
-// to unlock from a different thread will result in a runtime error.
-//
-// This implementation is suitable for simple critical sections where fairness
-// and reentrancy are not concerns.
-
-class Mutex final {
- os_unfair_lock_s lock_val = OS_UNFAIR_LOCK_INIT;
- mach_port_t owner = MACH_PORT_NULL;
-
- // API compatibility fields.
- unsigned char timed;
- unsigned char recursive;
- unsigned char robust;
- unsigned char pshared;
-
-public:
- LIBC_INLINE constexpr Mutex(bool is_timed, bool is_recursive, bool is_robust,
- bool is_pshared)
- : owner(MACH_PORT_NULL), timed(is_timed), recursive(is_recursive),
- robust(is_robust), pshared(is_pshared) {}
-
- LIBC_INLINE constexpr Mutex()
- : owner(MACH_PORT_NULL), timed(0), recursive(0), robust(0), pshared(0) {}
-
- LIBC_INLINE static MutexError init(Mutex *mutex, bool is_timed, bool is_recur,
- bool is_robust, bool is_pshared) {
- mutex->lock_val = OS_UNFAIR_LOCK_INIT;
- mutex->owner = MACH_PORT_NULL;
- mutex->timed = is_timed;
- mutex->recursive = is_recur;
- mutex->robust = is_robust;
- mutex->pshared = is_pshared;
- return MutexError::NONE;
- }
-
- LIBC_INLINE static MutexError destroy(Mutex *lock) {
- LIBC_ASSERT(lock->owner == MACH_PORT_NULL &&
- "Mutex destroyed while locked.");
- return MutexError::NONE;
- }
-
- LIBC_INLINE MutexError lock() {
- os_unfair_lock_lock(&lock_val);
- owner = mach_thread_self();
- return MutexError::NONE;
- }
-
- LIBC_INLINE MutexError timed_lock(internal::AbsTimeout abs_time) {
- while (true) {
- if (try_lock() == MutexError::NONE) {
- return MutexError::NONE;
- }
-
- // Manually check if the timeout has expired.
- struct timespec now;
- // The clock used here must match the clock used to create the
- // absolute timeout.
- clock_gettime(abs_time.is_realtime() ? CLOCK_REALTIME : CLOCK_MONOTONIC,
- &now);
- const timespec &target_ts = abs_time.get_timespec();
-
- if (now.tv_sec > target_ts.tv_sec || (now.tv_sec == target_ts.tv_sec &&
- now.tv_nsec >= target_ts.tv_nsec)) {
- // We might have acquired the lock between the last try_lock() and now.
- // To avoid returning TIMEOUT incorrectly, we do one last try_lock().
- if (try_lock() == MutexError::NONE)
- return MutexError::NONE;
- return MutexError::TIMEOUT;
- }
-
- sleep_briefly();
- }
- }
-
- LIBC_INLINE MutexError unlock() {
- // This check is crucial. It prevents both double-unlocks and unlocks
- // by threads that do not own the mutex.
- if (owner != mach_thread_self()) {
- return MutexError::UNLOCK_WITHOUT_LOCK;
- }
- owner = MACH_PORT_NULL;
- os_unfair_lock_unlock(&lock_val);
- return MutexError::NONE;
- }
-
- LIBC_INLINE MutexError try_lock() {
- if (os_unfair_lock_trylock(&lock_val)) {
- owner = mach_thread_self();
- return MutexError::NONE;
- }
- return MutexError::BUSY;
- }
-};
-
-} // namespace LIBC_NAMESPACE_DECL
-
-#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_DARWIN_MUTEX_H
>From 212cc76d2f791becc92b580122d8dc94247f6bda Mon Sep 17 00:00:00 2001
From: Shreeyash Pandey <shreeyash335 at gmail.com>
Date: Fri, 5 Dec 2025 18:35:58 +0530
Subject: [PATCH 5/8] [libc] linux/raw_mutex.h -> raw_mutex.h
---
libc/src/__support/threads/CndVar.h | 2 +-
.../__support/threads/linux/CMakeLists.txt | 30 ++-----------------
libc/src/__support/threads/linux/CndVar.cpp | 4 +--
libc/src/__support/threads/linux/rwlock.h | 2 +-
libc/src/__support/threads/raw_mutex.h | 6 ++--
libc/src/__support/threads/unix_mutex.h | 2 +-
libc/src/threads/linux/CMakeLists.txt | 2 +-
.../integration/src/pthread/CMakeLists.txt | 2 +-
.../src/pthread/pthread_rwlock_test.cpp | 2 +-
.../__support/threads/darwin/CMakeLists.txt | 11 +++++++
.../__support/threads/linux/CMakeLists.txt | 2 +-
.../threads/linux/raw_mutex_test.cpp | 2 +-
12 files changed, 26 insertions(+), 41 deletions(-)
create mode 100644 libc/test/src/__support/threads/darwin/CMakeLists.txt
diff --git a/libc/src/__support/threads/CndVar.h b/libc/src/__support/threads/CndVar.h
index 7b2a7126ca09c..901b652c553d8 100644
--- a/libc/src/__support/threads/CndVar.h
+++ b/libc/src/__support/threads/CndVar.h
@@ -12,8 +12,8 @@
#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/linux/raw_mutex.h" // RawMutex
#include "src/__support/threads/mutex.h" // Mutex
+#include "src/__support/threads/raw_mutex.h" // RawMutex
namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/__support/threads/linux/CMakeLists.txt b/libc/src/__support/threads/linux/CMakeLists.txt
index cc596d217d7d2..200a3b1529fec 100644
--- a/libc/src/__support/threads/linux/CMakeLists.txt
+++ b/libc/src/__support/threads/linux/CMakeLists.txt
@@ -31,29 +31,13 @@ else()
set(monotonicity_flags -DLIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY=0)
endif()
-add_header_library(
- raw_mutex
- HDRS
- mutex.h
- DEPENDS
- .futex_utils
- libc.src.__support.threads.sleep
- libc.src.__support.time.abs_timeout
- libc.src.__support.time.monotonicity
- libc.src.__support.CPP.optional
- libc.hdr.types.pid_t
- COMPILE_OPTIONS
- -DLIBC_COPT_RAW_MUTEX_DEFAULT_SPIN_COUNT=${LIBC_CONF_RAW_MUTEX_DEFAULT_SPIN_COUNT}
- ${monotonicity_flags}
-)
-
add_header_library(
rwlock
HDRS
rwlock.h
DEPENDS
.futex_utils
- .raw_mutex
+ libc.src.__support.threads.raw_mutex
libc.src.__support.common
libc.src.__support.OSUtil.osutil
libc.src.__support.CPP.limits
@@ -63,16 +47,6 @@ add_header_library(
${monotonicity_flags}
)
-add_header_library(
- mutex
- HDRS
- mutex.h
- DEPENDS
- .futex_utils
- .raw_mutex
- libc.src.__support.threads.mutex_common
-)
-
add_object_library(
thread
SRCS
@@ -119,7 +93,7 @@ add_object_library(
libc.src.__support.OSUtil.osutil
libc.src.__support.threads.linux.futex_word_type
libc.src.__support.threads.mutex
- libc.src.__support.threads.linux.raw_mutex
+ libc.src.__support.threads.raw_mutex
libc.src.__support.CPP.mutex
)
diff --git a/libc/src/__support/threads/linux/CndVar.cpp b/libc/src/__support/threads/linux/CndVar.cpp
index be74c18dddf31..60424673e819c 100644
--- a/libc/src/__support/threads/linux/CndVar.cpp
+++ b/libc/src/__support/threads/linux/CndVar.cpp
@@ -8,11 +8,11 @@
#include "src/__support/threads/CndVar.h"
#include "src/__support/CPP/mutex.h"
-#include "src/__support/OSUtil/syscall.h" // syscall_impl
+#include "src/__support/OSUtil/syscall.h" // syscall_impl
#include "src/__support/macros/config.h"
#include "src/__support/threads/linux/futex_word.h" // FutexWordType
-#include "src/__support/threads/linux/raw_mutex.h" // RawMutex
#include "src/__support/threads/mutex.h" // Mutex
+#include "src/__support/threads/raw_mutex.h" // RawMutex
#include <sys/syscall.h> // For syscall numbers.
diff --git a/libc/src/__support/threads/linux/rwlock.h b/libc/src/__support/threads/linux/rwlock.h
index 165e17239bbd5..9fb3ff972b588 100644
--- a/libc/src/__support/threads/linux/rwlock.h
+++ b/libc/src/__support/threads/linux/rwlock.h
@@ -22,7 +22,7 @@
#include "src/__support/threads/identifier.h"
#include "src/__support/threads/linux/futex_utils.h"
#include "src/__support/threads/linux/futex_word.h"
-#include "src/__support/threads/linux/raw_mutex.h"
+#include "src/__support/threads/raw_mutex.h"
#include "src/__support/threads/sleep.h"
#ifndef LIBC_COPT_RWLOCK_DEFAULT_SPIN_COUNT
diff --git a/libc/src/__support/threads/raw_mutex.h b/libc/src/__support/threads/raw_mutex.h
index c8f35a5785fd7..571ea405dd851 100644
--- a/libc/src/__support/threads/raw_mutex.h
+++ b/libc/src/__support/threads/raw_mutex.h
@@ -1,10 +1,10 @@
-//===--- Implementation of the RawMutex class ---------------*- C++ -*-===//
+//===--- Implementation of the RawMutex class -------------------*- 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_RAW_MUTEX_H
#define LLVM_LIBC_SRC___SUPPORT_THREADS_RAW_MUTEX_H
@@ -136,4 +136,4 @@ class RawMutex {
};
} // namespace LIBC_NAMESPACE_DECL
-#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_RAW_MUTEX_H
+#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_RAW_MUTEX_H
diff --git a/libc/src/__support/threads/unix_mutex.h b/libc/src/__support/threads/unix_mutex.h
index 31acd582d4c6c..626cee9d0913d 100644
--- a/libc/src/__support/threads/unix_mutex.h
+++ b/libc/src/__support/threads/unix_mutex.h
@@ -1,4 +1,4 @@
-//===--- Implementation of a Unix mutex class ------------------*- C++ -*-===//
+//===--- Implementation of a Unix mutex class -------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/libc/src/threads/linux/CMakeLists.txt b/libc/src/threads/linux/CMakeLists.txt
index 6c8e0845faf4c..3cbf2f85f3f9d 100644
--- a/libc/src/threads/linux/CMakeLists.txt
+++ b/libc/src/threads/linux/CMakeLists.txt
@@ -9,7 +9,7 @@ add_header_library(
libc.src.__support.CPP.mutex
libc.src.__support.OSUtil.osutil
libc.src.__support.threads.mutex
- libc.src.__support.threads.linux.raw_mutex
+ libc.src.__support.threads.raw_mutex
libc.src.__support.threads.linux.futex_utils
)
diff --git a/libc/test/integration/src/pthread/CMakeLists.txt b/libc/test/integration/src/pthread/CMakeLists.txt
index 251b009994ab5..b7414f2bea120 100644
--- a/libc/test/integration/src/pthread/CMakeLists.txt
+++ b/libc/test/integration/src/pthread/CMakeLists.txt
@@ -62,7 +62,7 @@ add_integration_test(
libc.src.pthread.pthread_rwlockattr_destroy
libc.src.pthread.pthread_rwlockattr_setpshared
libc.src.pthread.pthread_rwlockattr_setkind_np
- libc.src.__support.threads.linux.raw_mutex
+ libc.src.__support.threads.raw_mutex
libc.src.stdio.printf
libc.src.stdlib.getenv
libc.src.sys.mman.mmap
diff --git a/libc/test/integration/src/pthread/pthread_rwlock_test.cpp b/libc/test/integration/src/pthread/pthread_rwlock_test.cpp
index 205e9f74ea9a1..dddfb282ce167 100644
--- a/libc/test/integration/src/pthread/pthread_rwlock_test.cpp
+++ b/libc/test/integration/src/pthread/pthread_rwlock_test.cpp
@@ -12,8 +12,8 @@
#include "src/__support/CPP/new.h"
#include "src/__support/OSUtil/syscall.h"
#include "src/__support/macros/config.h"
-#include "src/__support/threads/linux/raw_mutex.h"
#include "src/__support/threads/linux/rwlock.h"
+#include "src/__support/threads/raw_mutex.h"
#include "src/__support/threads/sleep.h"
#include "src/pthread/pthread_create.h"
#include "src/pthread/pthread_join.h"
diff --git a/libc/test/src/__support/threads/darwin/CMakeLists.txt b/libc/test/src/__support/threads/darwin/CMakeLists.txt
new file mode 100644
index 0000000000000..4c399b4258d66
--- /dev/null
+++ b/libc/test/src/__support/threads/darwin/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_libc_test(
+ mutex_test
+ SUITE
+ libc-support-threads-tests
+ SRCS
+ mutex_test.cpp
+ DEPENDS
+ libc.src.__support.threads.mutex
+ libc.src.__support.threads.darwin.futex_utils
+ libc.src.__support.time.darwin.clock_gettime
+)
diff --git a/libc/test/src/__support/threads/linux/CMakeLists.txt b/libc/test/src/__support/threads/linux/CMakeLists.txt
index 4299a5617b8ff..a660e7ceb4490 100644
--- a/libc/test/src/__support/threads/linux/CMakeLists.txt
+++ b/libc/test/src/__support/threads/linux/CMakeLists.txt
@@ -5,7 +5,7 @@ add_libc_test(
SRCS
raw_mutex_test.cpp
DEPENDS
- libc.src.__support.threads.linux.raw_mutex
+ libc.src.__support.threads.raw_mutex
libc.src.sys.mman.mmap
libc.src.sys.mman.munmap
libc.src.stdlib.exit
diff --git a/libc/test/src/__support/threads/linux/raw_mutex_test.cpp b/libc/test/src/__support/threads/linux/raw_mutex_test.cpp
index dadc706421d06..6522ec75e619c 100644
--- a/libc/test/src/__support/threads/linux/raw_mutex_test.cpp
+++ b/libc/test/src/__support/threads/linux/raw_mutex_test.cpp
@@ -10,7 +10,7 @@
#include "include/llvm-libc-macros/linux/time-macros.h"
#include "src/__support/CPP/atomic.h"
#include "src/__support/OSUtil/syscall.h"
-#include "src/__support/threads/linux/raw_mutex.h"
+#include "src/__support/threads/raw_mutex.h"
#include "src/__support/threads/sleep.h"
#include "src/__support/time/clock_gettime.h"
#include "src/stdlib/exit.h"
>From eb03eff51fc7448f7a56b1e18798485f509c7b5a Mon Sep 17 00:00:00 2001
From: Shreeyash Pandey <shreeyash335 at gmail.com>
Date: Fri, 5 Dec 2025 18:50:35 +0530
Subject: [PATCH 6/8] [libc] "" -> <>
---
libc/src/__support/threads/raw_mutex.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/src/__support/threads/raw_mutex.h b/libc/src/__support/threads/raw_mutex.h
index 571ea405dd851..a5af02a3e1414 100644
--- a/libc/src/__support/threads/raw_mutex.h
+++ b/libc/src/__support/threads/raw_mutex.h
@@ -16,7 +16,7 @@
#include "src/__support/macros/optimization.h"
#include "src/__support/threads/sleep.h"
#include "src/__support/time/abs_timeout.h"
-#include "sys/errno.h"
+#include <sys/errno.h>
#include <stdio.h>
>From 390aca8acf2ecf0b024c80bdf0bf325334772fc3 Mon Sep 17 00:00:00 2001
From: Shreeyash Pandey <shreeyash335 at gmail.com>
Date: Fri, 5 Dec 2025 18:57:35 +0530
Subject: [PATCH 7/8] [libc] use hdr/errno_macros.h
Signed-off-by: Shreeyash Pandey <shreeyash335 at gmail.com>
---
libc/src/__support/threads/raw_mutex.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/src/__support/threads/raw_mutex.h b/libc/src/__support/threads/raw_mutex.h
index a5af02a3e1414..e68469ad531cc 100644
--- a/libc/src/__support/threads/raw_mutex.h
+++ b/libc/src/__support/threads/raw_mutex.h
@@ -8,6 +8,7 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_RAW_MUTEX_H
#define LLVM_LIBC_SRC___SUPPORT_THREADS_RAW_MUTEX_H
+#include "hdr/errno_macros.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/common.h"
#include "src/__support/libc_assert.h"
@@ -16,7 +17,6 @@
#include "src/__support/macros/optimization.h"
#include "src/__support/threads/sleep.h"
#include "src/__support/time/abs_timeout.h"
-#include <sys/errno.h>
#include <stdio.h>
>From 475c70fa69d31d7d372b517631efb25ae32ef7c8 Mon Sep 17 00:00:00 2001
From: Shreeyash Pandey <shreeyash335 at gmail.com>
Date: Fri, 5 Dec 2025 19:19:52 +0530
Subject: [PATCH 8/8] [libc] use time_units
---
libc/src/__support/threads/darwin/futex_utils.h | 4 +++-
libc/test/src/__support/threads/darwin/mutex_test.cpp | 3 ++-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/libc/src/__support/threads/darwin/futex_utils.h b/libc/src/__support/threads/darwin/futex_utils.h
index f880d09f621fc..65ac1ce0ab351 100644
--- a/libc/src/__support/threads/darwin/futex_utils.h
+++ b/libc/src/__support/threads/darwin/futex_utils.h
@@ -13,6 +13,7 @@
#include "src/__support/CPP/optional.h"
#include "src/__support/time/abs_timeout.h"
#include "src/__support/time/clock_conversion.h"
+#include "src/__support/time/units.h"
#include <os/os_sync_wait_on_address.h>
@@ -36,7 +37,8 @@ struct Futex : public cpp::Atomic<FutexWordType> {
long ret = 0;
if (timeout) {
// Assuming, OS_CLOCK_MACH_ABSOLUTE_TIME is equivalent to CLOCK_REALTIME
- uint64_t tnsec = timeout->get_timespec().tv_sec * 1000000000 +
+ using namespace time_units;
+ uint64_t tnsec = timeout->get_timespec().tv_sec * 1_s_ns +
timeout->get_timespec().tv_nsec;
ret = os_sync_wait_on_address_with_timeout(
reinterpret_cast<void *>(this), static_cast<uint64_t>(val),
diff --git a/libc/test/src/__support/threads/darwin/mutex_test.cpp b/libc/test/src/__support/threads/darwin/mutex_test.cpp
index b87da8670e422..a9df97bc94ebb 100644
--- a/libc/test/src/__support/threads/darwin/mutex_test.cpp
+++ b/libc/test/src/__support/threads/darwin/mutex_test.cpp
@@ -42,4 +42,5 @@ TEST(LlvmLibcSupportThreadsRawMutexTest, Timeout) {
ASSERT_TRUE(mutex.unlock());
}
-// TODO(bojle): add other tests a la linux
+// TODO(bojle): merge threads test for darwin and linux into one after
+// adding support for shared locks in darwin
More information about the libc-commits
mailing list