1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include <__assert> 10 #include <__system_error/throw_system_error.h> 11 #include <__thread/id.h> 12 #include <__utility/exception_guard.h> 13 #include <limits> 14 #include <mutex> 15 16 #include "include/atomic_support.h" 17 18 #if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB) 19 # pragma comment(lib, "pthread") 20 #endif 21 22 _LIBCPP_PUSH_MACROS 23 #include <__undef_macros> 24 25 _LIBCPP_BEGIN_NAMESPACE_STD 26 27 // ~mutex is defined elsewhere 28 29 void mutex::lock() { 30 int ec = __libcpp_mutex_lock(&__m_); 31 if (ec) 32 std::__throw_system_error(ec, "mutex lock failed"); 33 } 34 35 bool mutex::try_lock() noexcept { return __libcpp_mutex_trylock(&__m_); } 36 37 void mutex::unlock() noexcept { 38 int ec = __libcpp_mutex_unlock(&__m_); 39 (void)ec; 40 _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL( 41 ec == 0, "call to mutex::unlock failed. A possible reason is that the mutex wasn't locked"); 42 } 43 44 // recursive_mutex 45 46 recursive_mutex::recursive_mutex() { 47 int ec = __libcpp_recursive_mutex_init(&__m_); 48 if (ec) 49 std::__throw_system_error(ec, "recursive_mutex constructor failed"); 50 } 51 52 recursive_mutex::~recursive_mutex() { 53 int e = __libcpp_recursive_mutex_destroy(&__m_); 54 (void)e; 55 _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(e == 0, "call to ~recursive_mutex() failed"); 56 } 57 58 void recursive_mutex::lock() { 59 int ec = __libcpp_recursive_mutex_lock(&__m_); 60 if (ec) 61 std::__throw_system_error(ec, "recursive_mutex lock failed"); 62 } 63 64 void recursive_mutex::unlock() noexcept { 65 int e = __libcpp_recursive_mutex_unlock(&__m_); 66 (void)e; 67 _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL( 68 e == 0, "call to recursive_mutex::unlock() failed. A possible reason is that the mutex wasn't locked"); 69 } 70 71 bool recursive_mutex::try_lock() noexcept { return __libcpp_recursive_mutex_trylock(&__m_); } 72 73 // timed_mutex 74 75 timed_mutex::timed_mutex() : __locked_(false) {} 76 77 timed_mutex::~timed_mutex() { lock_guard<mutex> _(__m_); } 78 79 void timed_mutex::lock() { 80 unique_lock<mutex> lk(__m_); 81 while (__locked_) 82 __cv_.wait(lk); 83 __locked_ = true; 84 } 85 86 bool timed_mutex::try_lock() noexcept { 87 unique_lock<mutex> lk(__m_, try_to_lock); 88 if (lk.owns_lock() && !__locked_) { 89 __locked_ = true; 90 return true; 91 } 92 return false; 93 } 94 95 void timed_mutex::unlock() noexcept { 96 lock_guard<mutex> _(__m_); 97 __locked_ = false; 98 __cv_.notify_one(); 99 } 100 101 // recursive_timed_mutex 102 103 recursive_timed_mutex::recursive_timed_mutex() : __count_(0), __id_{} {} 104 105 recursive_timed_mutex::~recursive_timed_mutex() { lock_guard<mutex> _(__m_); } 106 107 void recursive_timed_mutex::lock() { 108 __thread_id id = this_thread::get_id(); 109 unique_lock<mutex> lk(__m_); 110 if (id == __id_) { 111 if (__count_ == numeric_limits<size_t>::max()) 112 std::__throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached"); 113 ++__count_; 114 return; 115 } 116 while (__count_ != 0) 117 __cv_.wait(lk); 118 __count_ = 1; 119 __id_ = id; 120 } 121 122 bool recursive_timed_mutex::try_lock() noexcept { 123 __thread_id id = this_thread::get_id(); 124 unique_lock<mutex> lk(__m_, try_to_lock); 125 if (lk.owns_lock() && (__count_ == 0 || id == __id_)) { 126 if (__count_ == numeric_limits<size_t>::max()) 127 return false; 128 ++__count_; 129 __id_ = id; 130 return true; 131 } 132 return false; 133 } 134 135 void recursive_timed_mutex::unlock() noexcept { 136 unique_lock<mutex> lk(__m_); 137 if (--__count_ == 0) { 138 __id_.__reset(); 139 lk.unlock(); 140 __cv_.notify_one(); 141 } 142 } 143 144 _LIBCPP_END_NAMESPACE_STD 145 146 _LIBCPP_POP_MACROS 147