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 <limits> 10 #include <mutex> 11 #include <system_error> 12 13 #include "include/atomic_support.h" 14 15 #ifndef _LIBCPP_HAS_NO_THREADS 16 # if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB) 17 # pragma comment(lib, "pthread") 18 # endif 19 #endif 20 21 _LIBCPP_PUSH_MACROS 22 #include <__undef_macros> 23 24 _LIBCPP_BEGIN_NAMESPACE_STD 25 26 #ifndef _LIBCPP_HAS_NO_THREADS 27 28 const defer_lock_t defer_lock{}; 29 const try_to_lock_t try_to_lock{}; 30 const adopt_lock_t adopt_lock{}; 31 32 // ~mutex is defined elsewhere 33 34 void 35 mutex::lock() 36 { 37 int ec = __libcpp_mutex_lock(&__m_); 38 if (ec) 39 __throw_system_error(ec, "mutex lock failed"); 40 } 41 42 bool 43 mutex::try_lock() noexcept 44 { 45 return __libcpp_mutex_trylock(&__m_); 46 } 47 48 void 49 mutex::unlock() noexcept 50 { 51 int ec = __libcpp_mutex_unlock(&__m_); 52 (void)ec; 53 _LIBCPP_ASSERT(ec == 0, "call to mutex::unlock failed"); 54 } 55 56 // recursive_mutex 57 58 recursive_mutex::recursive_mutex() 59 { 60 int ec = __libcpp_recursive_mutex_init(&__m_); 61 if (ec) 62 __throw_system_error(ec, "recursive_mutex constructor failed"); 63 } 64 65 recursive_mutex::~recursive_mutex() 66 { 67 int e = __libcpp_recursive_mutex_destroy(&__m_); 68 (void)e; 69 _LIBCPP_ASSERT(e == 0, "call to ~recursive_mutex() failed"); 70 } 71 72 void 73 recursive_mutex::lock() 74 { 75 int ec = __libcpp_recursive_mutex_lock(&__m_); 76 if (ec) 77 __throw_system_error(ec, "recursive_mutex lock failed"); 78 } 79 80 void 81 recursive_mutex::unlock() noexcept 82 { 83 int e = __libcpp_recursive_mutex_unlock(&__m_); 84 (void)e; 85 _LIBCPP_ASSERT(e == 0, "call to recursive_mutex::unlock() failed"); 86 } 87 88 bool 89 recursive_mutex::try_lock() noexcept 90 { 91 return __libcpp_recursive_mutex_trylock(&__m_); 92 } 93 94 // timed_mutex 95 96 timed_mutex::timed_mutex() 97 : __locked_(false) 98 { 99 } 100 101 timed_mutex::~timed_mutex() 102 { 103 lock_guard<mutex> _(__m_); 104 } 105 106 void 107 timed_mutex::lock() 108 { 109 unique_lock<mutex> lk(__m_); 110 while (__locked_) 111 __cv_.wait(lk); 112 __locked_ = true; 113 } 114 115 bool 116 timed_mutex::try_lock() noexcept 117 { 118 unique_lock<mutex> lk(__m_, try_to_lock); 119 if (lk.owns_lock() && !__locked_) 120 { 121 __locked_ = true; 122 return true; 123 } 124 return false; 125 } 126 127 void 128 timed_mutex::unlock() noexcept 129 { 130 lock_guard<mutex> _(__m_); 131 __locked_ = false; 132 __cv_.notify_one(); 133 } 134 135 // recursive_timed_mutex 136 137 recursive_timed_mutex::recursive_timed_mutex() 138 : __count_(0), 139 __id_{} 140 { 141 } 142 143 recursive_timed_mutex::~recursive_timed_mutex() 144 { 145 lock_guard<mutex> _(__m_); 146 } 147 148 void 149 recursive_timed_mutex::lock() 150 { 151 __thread_id id = this_thread::get_id(); 152 unique_lock<mutex> lk(__m_); 153 if (id ==__id_) 154 { 155 if (__count_ == numeric_limits<size_t>::max()) 156 __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached"); 157 ++__count_; 158 return; 159 } 160 while (__count_ != 0) 161 __cv_.wait(lk); 162 __count_ = 1; 163 __id_ = id; 164 } 165 166 bool 167 recursive_timed_mutex::try_lock() noexcept 168 { 169 __thread_id id = this_thread::get_id(); 170 unique_lock<mutex> lk(__m_, try_to_lock); 171 if (lk.owns_lock() && (__count_ == 0 || id == __id_)) 172 { 173 if (__count_ == numeric_limits<size_t>::max()) 174 return false; 175 ++__count_; 176 __id_ = id; 177 return true; 178 } 179 return false; 180 } 181 182 void 183 recursive_timed_mutex::unlock() noexcept 184 { 185 unique_lock<mutex> lk(__m_); 186 if (--__count_ == 0) 187 { 188 __id_.__reset(); 189 lk.unlock(); 190 __cv_.notify_one(); 191 } 192 } 193 194 #endif // !_LIBCPP_HAS_NO_THREADS 195 196 // If dispatch_once_f ever handles C++ exceptions, and if one can get to it 197 // without illegal macros (unexpected macros not beginning with _UpperCase or 198 // __lowercase), and if it stops spinning waiting threads, then call_once should 199 // call into dispatch_once_f instead of here. Relevant radar this code needs to 200 // keep in sync with: 7741191. 201 202 #ifndef _LIBCPP_HAS_NO_THREADS 203 static constinit __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER; 204 static constinit __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER; 205 #endif 206 207 void __call_once(volatile once_flag::_State_type& flag, void* arg, 208 void (*func)(void*)) 209 { 210 #if defined(_LIBCPP_HAS_NO_THREADS) 211 if (flag == 0) 212 { 213 #ifndef _LIBCPP_NO_EXCEPTIONS 214 try 215 { 216 #endif // _LIBCPP_NO_EXCEPTIONS 217 flag = 1; 218 func(arg); 219 flag = ~once_flag::_State_type(0); 220 #ifndef _LIBCPP_NO_EXCEPTIONS 221 } 222 catch (...) 223 { 224 flag = 0; 225 throw; 226 } 227 #endif // _LIBCPP_NO_EXCEPTIONS 228 } 229 #else // !_LIBCPP_HAS_NO_THREADS 230 __libcpp_mutex_lock(&mut); 231 while (flag == 1) 232 __libcpp_condvar_wait(&cv, &mut); 233 if (flag == 0) 234 { 235 #ifndef _LIBCPP_NO_EXCEPTIONS 236 try 237 { 238 #endif // _LIBCPP_NO_EXCEPTIONS 239 __libcpp_relaxed_store(&flag, once_flag::_State_type(1)); 240 __libcpp_mutex_unlock(&mut); 241 func(arg); 242 __libcpp_mutex_lock(&mut); 243 __libcpp_atomic_store(&flag, ~once_flag::_State_type(0), 244 _AO_Release); 245 __libcpp_mutex_unlock(&mut); 246 __libcpp_condvar_broadcast(&cv); 247 #ifndef _LIBCPP_NO_EXCEPTIONS 248 } 249 catch (...) 250 { 251 __libcpp_mutex_lock(&mut); 252 __libcpp_relaxed_store(&flag, once_flag::_State_type(0)); 253 __libcpp_mutex_unlock(&mut); 254 __libcpp_condvar_broadcast(&cv); 255 throw; 256 } 257 #endif // _LIBCPP_NO_EXCEPTIONS 258 } 259 else 260 __libcpp_mutex_unlock(&mut); 261 #endif // !_LIBCPP_HAS_NO_THREADS 262 } 263 264 _LIBCPP_END_NAMESPACE_STD 265 266 _LIBCPP_POP_MACROS 267