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