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