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