|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // 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 <__assert> | 
|  | #include <__thread/id.h> | 
|  | #include <__utility/exception_guard.h> | 
|  | #include <limits> | 
|  | #include <mutex> | 
|  |  | 
|  | #include "include/atomic_support.h" | 
|  |  | 
|  | #if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB) | 
|  | #  pragma comment(lib, "pthread") | 
|  | #endif | 
|  |  | 
|  | _LIBCPP_PUSH_MACROS | 
|  | #include <__undef_macros> | 
|  |  | 
|  | _LIBCPP_BEGIN_NAMESPACE_STD | 
|  |  | 
|  | // ~mutex is defined elsewhere | 
|  |  | 
|  | void mutex::lock() { | 
|  | int ec = __libcpp_mutex_lock(&__m_); | 
|  | if (ec) | 
|  | __throw_system_error(ec, "mutex lock failed"); | 
|  | } | 
|  |  | 
|  | bool mutex::try_lock() noexcept { return __libcpp_mutex_trylock(&__m_); } | 
|  |  | 
|  | void mutex::unlock() noexcept { | 
|  | int ec = __libcpp_mutex_unlock(&__m_); | 
|  | (void)ec; | 
|  | _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL( | 
|  | ec == 0, "call to mutex::unlock failed. A possible reason is that the mutex wasn't locked"); | 
|  | } | 
|  |  | 
|  | // recursive_mutex | 
|  |  | 
|  | recursive_mutex::recursive_mutex() { | 
|  | int ec = __libcpp_recursive_mutex_init(&__m_); | 
|  | if (ec) | 
|  | __throw_system_error(ec, "recursive_mutex constructor failed"); | 
|  | } | 
|  |  | 
|  | recursive_mutex::~recursive_mutex() { | 
|  | int e = __libcpp_recursive_mutex_destroy(&__m_); | 
|  | (void)e; | 
|  | _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(e == 0, "call to ~recursive_mutex() failed"); | 
|  | } | 
|  |  | 
|  | void recursive_mutex::lock() { | 
|  | int ec = __libcpp_recursive_mutex_lock(&__m_); | 
|  | if (ec) | 
|  | __throw_system_error(ec, "recursive_mutex lock failed"); | 
|  | } | 
|  |  | 
|  | void recursive_mutex::unlock() noexcept { | 
|  | int e = __libcpp_recursive_mutex_unlock(&__m_); | 
|  | (void)e; | 
|  | _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL( | 
|  | e == 0, "call to recursive_mutex::unlock() failed. A possible reason is that the mutex wasn't locked"); | 
|  | } | 
|  |  | 
|  | bool recursive_mutex::try_lock() noexcept { return __libcpp_recursive_mutex_trylock(&__m_); } | 
|  |  | 
|  | // timed_mutex | 
|  |  | 
|  | timed_mutex::timed_mutex() : __locked_(false) {} | 
|  |  | 
|  | timed_mutex::~timed_mutex() { lock_guard<mutex> _(__m_); } | 
|  |  | 
|  | void timed_mutex::lock() { | 
|  | unique_lock<mutex> lk(__m_); | 
|  | while (__locked_) | 
|  | __cv_.wait(lk); | 
|  | __locked_ = true; | 
|  | } | 
|  |  | 
|  | bool timed_mutex::try_lock() noexcept { | 
|  | unique_lock<mutex> lk(__m_, try_to_lock); | 
|  | if (lk.owns_lock() && !__locked_) { | 
|  | __locked_ = true; | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void timed_mutex::unlock() noexcept { | 
|  | lock_guard<mutex> _(__m_); | 
|  | __locked_ = false; | 
|  | __cv_.notify_one(); | 
|  | } | 
|  |  | 
|  | // recursive_timed_mutex | 
|  |  | 
|  | recursive_timed_mutex::recursive_timed_mutex() : __count_(0), __id_{} {} | 
|  |  | 
|  | recursive_timed_mutex::~recursive_timed_mutex() { lock_guard<mutex> _(__m_); } | 
|  |  | 
|  | void recursive_timed_mutex::lock() { | 
|  | __thread_id id = this_thread::get_id(); | 
|  | unique_lock<mutex> lk(__m_); | 
|  | if (id == __id_) { | 
|  | if (__count_ == numeric_limits<size_t>::max()) | 
|  | __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached"); | 
|  | ++__count_; | 
|  | return; | 
|  | } | 
|  | while (__count_ != 0) | 
|  | __cv_.wait(lk); | 
|  | __count_ = 1; | 
|  | __id_    = id; | 
|  | } | 
|  |  | 
|  | bool recursive_timed_mutex::try_lock() noexcept { | 
|  | __thread_id id = this_thread::get_id(); | 
|  | unique_lock<mutex> lk(__m_, try_to_lock); | 
|  | if (lk.owns_lock() && (__count_ == 0 || id == __id_)) { | 
|  | if (__count_ == numeric_limits<size_t>::max()) | 
|  | return false; | 
|  | ++__count_; | 
|  | __id_ = id; | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void recursive_timed_mutex::unlock() noexcept { | 
|  | unique_lock<mutex> lk(__m_); | 
|  | if (--__count_ == 0) { | 
|  | __id_.__reset(); | 
|  | lk.unlock(); | 
|  | __cv_.notify_one(); | 
|  | } | 
|  | } | 
|  |  | 
|  | _LIBCPP_END_NAMESPACE_STD | 
|  |  | 
|  | _LIBCPP_POP_MACROS |