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