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 pthread_mutex_destroy(&__m_); 27 } 28 29 void 30 mutex::lock() 31 { 32 int ec = pthread_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 pthread_mutex_trylock(&__m_) == 0; 41 } 42 43 void 44 mutex::unlock() _NOEXCEPT 45 { 46 int ec = pthread_mutex_unlock(&__m_); 47 (void)ec; 48 assert(ec == 0); 49 } 50 51 // recursive_mutex 52 53 recursive_mutex::recursive_mutex() 54 { 55 pthread_mutexattr_t attr; 56 int ec = pthread_mutexattr_init(&attr); 57 if (ec) 58 goto fail; 59 ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 60 if (ec) 61 { 62 pthread_mutexattr_destroy(&attr); 63 goto fail; 64 } 65 ec = pthread_mutex_init(&__m_, &attr); 66 if (ec) 67 { 68 pthread_mutexattr_destroy(&attr); 69 goto fail; 70 } 71 ec = pthread_mutexattr_destroy(&attr); 72 if (ec) 73 { 74 pthread_mutex_destroy(&__m_); 75 goto fail; 76 } 77 return; 78 fail: 79 __throw_system_error(ec, "recursive_mutex constructor failed"); 80 } 81 82 recursive_mutex::~recursive_mutex() 83 { 84 int e = pthread_mutex_destroy(&__m_); 85 (void)e; 86 assert(e == 0); 87 } 88 89 void 90 recursive_mutex::lock() 91 { 92 int ec = pthread_mutex_lock(&__m_); 93 if (ec) 94 __throw_system_error(ec, "recursive_mutex lock failed"); 95 } 96 97 void 98 recursive_mutex::unlock() _NOEXCEPT 99 { 100 int e = pthread_mutex_unlock(&__m_); 101 (void)e; 102 assert(e == 0); 103 } 104 105 bool 106 recursive_mutex::try_lock() _NOEXCEPT 107 { 108 return pthread_mutex_trylock(&__m_) == 0; 109 } 110 111 // timed_mutex 112 113 timed_mutex::timed_mutex() 114 : __locked_(false) 115 { 116 } 117 118 timed_mutex::~timed_mutex() 119 { 120 lock_guard<mutex> _(__m_); 121 } 122 123 void 124 timed_mutex::lock() 125 { 126 unique_lock<mutex> lk(__m_); 127 while (__locked_) 128 __cv_.wait(lk); 129 __locked_ = true; 130 } 131 132 bool 133 timed_mutex::try_lock() _NOEXCEPT 134 { 135 unique_lock<mutex> lk(__m_, try_to_lock); 136 if (lk.owns_lock() && !__locked_) 137 { 138 __locked_ = true; 139 return true; 140 } 141 return false; 142 } 143 144 void 145 timed_mutex::unlock() _NOEXCEPT 146 { 147 lock_guard<mutex> _(__m_); 148 __locked_ = false; 149 __cv_.notify_one(); 150 } 151 152 // recursive_timed_mutex 153 154 recursive_timed_mutex::recursive_timed_mutex() 155 : __count_(0), 156 __id_(0) 157 { 158 } 159 160 recursive_timed_mutex::~recursive_timed_mutex() 161 { 162 lock_guard<mutex> _(__m_); 163 } 164 165 void 166 recursive_timed_mutex::lock() 167 { 168 pthread_t id = pthread_self(); 169 unique_lock<mutex> lk(__m_); 170 if (pthread_equal(id, __id_)) 171 { 172 if (__count_ == numeric_limits<size_t>::max()) 173 __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached"); 174 ++__count_; 175 return; 176 } 177 while (__count_ != 0) 178 __cv_.wait(lk); 179 __count_ = 1; 180 __id_ = id; 181 } 182 183 bool 184 recursive_timed_mutex::try_lock() _NOEXCEPT 185 { 186 pthread_t id = pthread_self(); 187 unique_lock<mutex> lk(__m_, try_to_lock); 188 if (lk.owns_lock() && (__count_ == 0 || pthread_equal(id, __id_))) 189 { 190 if (__count_ == numeric_limits<size_t>::max()) 191 return false; 192 ++__count_; 193 __id_ = id; 194 return true; 195 } 196 return false; 197 } 198 199 void 200 recursive_timed_mutex::unlock() _NOEXCEPT 201 { 202 unique_lock<mutex> lk(__m_); 203 if (--__count_ == 0) 204 { 205 __id_ = 0; 206 lk.unlock(); 207 __cv_.notify_one(); 208 } 209 } 210 211 #endif // !_LIBCPP_HAS_NO_THREADS 212 213 // If dispatch_once_f ever handles C++ exceptions, and if one can get to it 214 // without illegal macros (unexpected macros not beginning with _UpperCase or 215 // __lowercase), and if it stops spinning waiting threads, then call_once should 216 // call into dispatch_once_f instead of here. Relevant radar this code needs to 217 // keep in sync with: 7741191. 218 219 #ifndef _LIBCPP_HAS_NO_THREADS 220 static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; 221 static pthread_cond_t cv = PTHREAD_COND_INITIALIZER; 222 #endif 223 224 /// NOTE: Changes to flag are done via relaxed atomic stores 225 /// even though the accesses are protected by a mutex because threads 226 /// just entering 'call_once` concurrently read from flag. 227 void 228 __call_once(volatile unsigned long& flag, void* arg, void(*func)(void*)) 229 { 230 #if defined(_LIBCPP_HAS_NO_THREADS) 231 if (flag == 0) 232 { 233 #ifndef _LIBCPP_NO_EXCEPTIONS 234 try 235 { 236 #endif // _LIBCPP_NO_EXCEPTIONS 237 flag = 1; 238 func(arg); 239 flag = ~0ul; 240 #ifndef _LIBCPP_NO_EXCEPTIONS 241 } 242 catch (...) 243 { 244 flag = 0ul; 245 throw; 246 } 247 #endif // _LIBCPP_NO_EXCEPTIONS 248 } 249 #else // !_LIBCPP_HAS_NO_THREADS 250 pthread_mutex_lock(&mut); 251 while (flag == 1) 252 pthread_cond_wait(&cv, &mut); 253 if (flag == 0) 254 { 255 #ifndef _LIBCPP_NO_EXCEPTIONS 256 try 257 { 258 #endif // _LIBCPP_NO_EXCEPTIONS 259 __libcpp_relaxed_store(&flag, 1ul); 260 pthread_mutex_unlock(&mut); 261 func(arg); 262 pthread_mutex_lock(&mut); 263 __libcpp_relaxed_store(&flag, ~0ul); 264 pthread_mutex_unlock(&mut); 265 pthread_cond_broadcast(&cv); 266 #ifndef _LIBCPP_NO_EXCEPTIONS 267 } 268 catch (...) 269 { 270 pthread_mutex_lock(&mut); 271 __libcpp_relaxed_store(&flag, 0ul); 272 pthread_mutex_unlock(&mut); 273 pthread_cond_broadcast(&cv); 274 throw; 275 } 276 #endif // _LIBCPP_NO_EXCEPTIONS 277 } 278 else 279 pthread_mutex_unlock(&mut); 280 #endif // !_LIBCPP_HAS_NO_THREADS 281 282 } 283 284 _LIBCPP_END_NAMESPACE_STD 285