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