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