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