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