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