diff --git a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake index 4e9a9b66a63a7..ad675c4358ad4 100644 --- a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake +++ b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake @@ -116,6 +116,10 @@ function(_get_compile_options_from_config output_var) list(APPEND config_options "-DLIBC_THREAD_MODE=${LIBC_CONF_THREAD_MODE}") 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/hdr/errno_macros.h b/libc/hdr/errno_macros.h index 27ea49977d8c8..e2913f45a8ad9 100644 --- a/libc/hdr/errno_macros.h +++ b/libc/hdr/errno_macros.h @@ -15,7 +15,9 @@ #include #include "include/llvm-libc-macros/error-number-macros.h" -#else // __linux__ +#elif defined(__APPLE__) +#include +#else // __APPLE__ #include "include/llvm-libc-macros/generic-error-number-macros.h" #endif diff --git a/libc/include/errno.h.def b/libc/include/errno.h.def index aa1f6c9e48444..0ac8e57f7a158 100644 --- a/libc/include/errno.h.def +++ b/libc/include/errno.h.def @@ -21,8 +21,14 @@ #include "llvm-libc-macros/linux/error-number-macros.h" -#else // __linux__ +#elif defined(__APPLE__) + +#include + +#else // __APPLE__ + #include "llvm-libc-macros/generic-error-number-macros.h" + #endif __BEGIN_C_DECLS diff --git a/libc/src/__support/threads/CMakeLists.txt b/libc/src/__support/threads/CMakeLists.txt index f8a44937721b4..dc1445634da2b 100644 --- a/libc/src/__support/threads/CMakeLists.txt +++ b/libc/src/__support/threads/CMakeLists.txt @@ -23,31 +23,54 @@ 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( + raw_mutex + HDRS + raw_mutex.h + COMPILE_OPTIONS + ${monotonicity_flags} + 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 + ) + + add_header_library( + unix_mutex + HDRS + unix_mutex.h + DEPENDS + .raw_mutex + ) + add_header_library( mutex HDRS - mutex.h + mutex.h DEPENDS - .${LIBC_TARGET_OS}.mutex + .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/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..f880d09f621fc --- /dev/null +++ b/libc/src/__support/threads/darwin/futex_utils.h @@ -0,0 +1,77 @@ +//===--- 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 + +namespace LIBC_NAMESPACE_DECL { + +using FutexWordType = uint32_t; + +struct Futex : public cpp::Atomic { + using cpp::Atomic::Atomic; + using Timeout = internal::AbsTimeout; + + LIBC_INLINE long wait(FutexWordType val, cpp::optional 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. + + 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(this), static_cast(val), + sizeof(FutexWordType), OS_SYNC_WAIT_ON_ADDRESS_NONE, + OS_CLOCK_MACH_ABSOLUTE_TIME, tnsec); + } else { + ret = os_sync_wait_on_address( + reinterpret_cast(this), static_cast(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; + } + } + + LIBC_INLINE long notify_one(bool /* is_shared */) { + // TODO(bojle): deal with is_shared + return os_sync_wake_by_address_any(reinterpret_cast(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(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/linux/CMakeLists.txt b/libc/src/__support/threads/linux/CMakeLists.txt index 39d2c6fef0fed..cc596d217d7d2 100644 --- a/libc/src/__support/threads/linux/CMakeLists.txt +++ b/libc/src/__support/threads/linux/CMakeLists.txt @@ -21,7 +21,7 @@ add_header_library( libc.src.__support.CPP.atomic libc.src.__support.CPP.limits libc.src.__support.CPP.optional - libc.src.__support.time.linux.abs_timeout + libc.src.__support.time.abs_timeout ) set(monotonicity_flags) @@ -38,8 +38,8 @@ add_header_library( DEPENDS .futex_utils libc.src.__support.threads.sleep - libc.src.__support.time.linux.abs_timeout - libc.src.__support.time.linux.monotonicity + libc.src.__support.time.abs_timeout + libc.src.__support.time.monotonicity libc.src.__support.CPP.optional libc.hdr.types.pid_t COMPILE_OPTIONS diff --git a/libc/src/__support/threads/linux/futex_utils.h b/libc/src/__support/threads/linux/futex_utils.h index 943a99ab38c8c..e1cfa36566555 100644 --- a/libc/src/__support/threads/linux/futex_utils.h +++ b/libc/src/__support/threads/linux/futex_utils.h @@ -16,7 +16,7 @@ #include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" #include "src/__support/threads/linux/futex_word.h" -#include "src/__support/time/linux/abs_timeout.h" +#include "src/__support/time/abs_timeout.h" #include #include diff --git a/libc/src/__support/threads/linux/rwlock.h b/libc/src/__support/threads/linux/rwlock.h index f7aeb5b709aa3..165e17239bbd5 100644 --- a/libc/src/__support/threads/linux/rwlock.h +++ b/libc/src/__support/threads/linux/rwlock.h @@ -35,7 +35,7 @@ #endif #if LIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY -#include "src/__support/time/linux/monotonicity.h" +#include "src/__support/time/monotonicity.h" #endif namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/__support/threads/mutex.h b/libc/src/__support/threads/mutex.h index f64f7e7b40082..25feea891e429 100644 --- a/libc/src/__support/threads/mutex.h +++ b/libc/src/__support/threads/mutex.h @@ -40,9 +40,9 @@ // few global locks. So, to avoid static initialization order fiasco, we // want the constructors of the Mutex classes to be constexprs. -#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 #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 87% rename from libc/src/__support/threads/linux/raw_mutex.h rename to libc/src/__support/threads/raw_mutex.h index 47f0aa70f1c46..c8f35a5785fd7 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,17 +14,25 @@ #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/linux/abs_timeout.h" +#include "src/__support/time/abs_timeout.h" +#include "sys/errno.h" + +#include + +#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/linux/monotonicity.h" +#include "src/__support/time/monotonicity.h" #endif #ifndef LIBC_COPT_RAW_MUTEX_DEFAULT_SPIN_COUNT @@ -93,7 +101,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 +132,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 { diff --git a/libc/src/__support/time/CMakeLists.txt b/libc/src/__support/time/CMakeLists.txt index 3851037e4161f..b90f977b00fe5 100644 --- a/libc/src/__support/time/CMakeLists.txt +++ b/libc/src/__support/time/CMakeLists.txt @@ -28,3 +28,32 @@ if(TARGET libc.src.__support.time.${LIBC_TARGET_OS}.clock_settime) libc.src.__support.time.${LIBC_TARGET_OS}.clock_settime ) endif() + +add_header_library( + abs_timeout + HDRS + abs_timeout.h + DEPENDS + libc.hdr.types.struct_timespec + libc.src.__support.time.units + libc.src.__support.CPP.expected +) + +add_header_library( + clock_conversion + HDRS + clock_conversion.h + DEPENDS + .clock_gettime + libc.src.__support.time.units +) + +add_header_library( + monotonicity + HDRS + monotonicity.h + DEPENDS + .clock_conversion + .abs_timeout + libc.hdr.time_macros +) diff --git a/libc/src/__support/time/linux/abs_timeout.h b/libc/src/__support/time/abs_timeout.h similarity index 85% rename from libc/src/__support/time/linux/abs_timeout.h rename to libc/src/__support/time/abs_timeout.h index 37e602672208f..23ad52f530545 100644 --- a/libc/src/__support/time/linux/abs_timeout.h +++ b/libc/src/__support/time/abs_timeout.h @@ -1,13 +1,13 @@ -//===--- Linux absolute timeout ---------------------------------*- C++ -*-===// +//===--- absolute timeout ---------------------------------*- 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_TIME_LINUX_ABS_TIMEOUT_H -#define LLVM_LIBC_SRC___SUPPORT_TIME_LINUX_ABS_TIMEOUT_H +#ifndef LLVM_LIBC_SRC___SUPPORT_TIME_ABS_TIMEOUT_H +#define LLVM_LIBC_SRC___SUPPORT_TIME_ABS_TIMEOUT_H #include "hdr/time_macros.h" #include "hdr/types/struct_timespec.h" @@ -47,4 +47,4 @@ class AbsTimeout { } // namespace internal } // namespace LIBC_NAMESPACE_DECL -#endif // LLVM_LIBC_SRC___SUPPORT_TIME_LINUX_ABS_TIMEOUT_H +#endif // LLVM_LIBC_SRC___SUPPORT_TIME_ABS_TIMEOUT_H diff --git a/libc/src/__support/time/linux/CMakeLists.txt b/libc/src/__support/time/linux/CMakeLists.txt index 478529502b403..a7bdb7b36be49 100644 --- a/libc/src/__support/time/linux/CMakeLists.txt +++ b/libc/src/__support/time/linux/CMakeLists.txt @@ -28,32 +28,3 @@ add_object_library( libc.src.__support.error_or libc.src.__support.OSUtil.osutil ) - -add_header_library( - clock_conversion - HDRS - clock_conversion.h - DEPENDS - .clock_gettime - libc.src.__support.time.units -) - -add_header_library( - abs_timeout - HDRS - abs_timeout.h - DEPENDS - libc.hdr.types.struct_timespec - libc.src.__support.time.units - libc.src.__support.CPP.expected -) - -add_header_library( - monotonicity - HDRS - monotonicity.h - DEPENDS - .clock_conversion - .abs_timeout - libc.hdr.time_macros -) diff --git a/libc/src/__support/time/linux/monotonicity.h b/libc/src/__support/time/monotonicity.h similarity index 79% rename from libc/src/__support/time/linux/monotonicity.h rename to libc/src/__support/time/monotonicity.h index c7234db2e64c4..4fee76da2a62e 100644 --- a/libc/src/__support/time/linux/monotonicity.h +++ b/libc/src/__support/time/monotonicity.h @@ -1,19 +1,19 @@ -//===--- timeout linux implementation ---------------------------*- C++ -*-===// +//===--- timeout implementation ---------------------------*- 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_TIME_LINUX_MONOTONICITY_H -#define LLVM_LIBC_SRC___SUPPORT_TIME_LINUX_MONOTONICITY_H +#ifndef LLVM_LIBC_SRC___SUPPORT_TIME_MONOTONICITY_H +#define LLVM_LIBC_SRC___SUPPORT_TIME_MONOTONICITY_H #include "hdr/time_macros.h" #include "src/__support/libc_assert.h" #include "src/__support/macros/config.h" -#include "src/__support/time/linux/abs_timeout.h" -#include "src/__support/time/linux/clock_conversion.h" +#include "src/__support/time/abs_timeout.h" +#include "src/__support/time/clock_conversion.h" namespace LIBC_NAMESPACE_DECL { namespace internal { // This function is separated from abs_timeout. @@ -41,4 +41,4 @@ LIBC_INLINE void ensure_monotonicity(AbsTimeout &timeout) { } // namespace internal } // namespace LIBC_NAMESPACE_DECL -#endif // LLVM_LIBC_SRC___SUPPORT_TIME_LINUX_MONOTONICITY_H +#endif // LLVM_LIBC_SRC___SUPPORT_TIME_MONOTONICITY_H diff --git a/libc/src/pthread/pthread_rwlock_clockwrlock.cpp b/libc/src/pthread/pthread_rwlock_clockwrlock.cpp index 8f58c7f24bb10..787a1b1484df7 100644 --- a/libc/src/pthread/pthread_rwlock_clockwrlock.cpp +++ b/libc/src/pthread/pthread_rwlock_clockwrlock.cpp @@ -12,7 +12,7 @@ #include "src/__support/common.h" #include "src/__support/macros/config.h" #include "src/__support/threads/linux/rwlock.h" -#include "src/__support/time/linux/abs_timeout.h" +#include "src/__support/time/abs_timeout.h" #include diff --git a/libc/src/pthread/pthread_rwlock_timedrdlock.cpp b/libc/src/pthread/pthread_rwlock_timedrdlock.cpp index fcddfed224906..745da508cf140 100644 --- a/libc/src/pthread/pthread_rwlock_timedrdlock.cpp +++ b/libc/src/pthread/pthread_rwlock_timedrdlock.cpp @@ -13,7 +13,7 @@ #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" #include "src/__support/threads/linux/rwlock.h" -#include "src/__support/time/linux/abs_timeout.h" +#include "src/__support/time/abs_timeout.h" #include diff --git a/libc/src/pthread/pthread_rwlock_timedwrlock.cpp b/libc/src/pthread/pthread_rwlock_timedwrlock.cpp index d2dc70e992e82..9666fc5b47284 100644 --- a/libc/src/pthread/pthread_rwlock_timedwrlock.cpp +++ b/libc/src/pthread/pthread_rwlock_timedwrlock.cpp @@ -13,7 +13,7 @@ #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" #include "src/__support/threads/linux/rwlock.h" -#include "src/__support/time/linux/abs_timeout.h" +#include "src/__support/time/abs_timeout.h" #include 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