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