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 19const defer_lock_t defer_lock = {}; 20const try_to_lock_t try_to_lock = {}; 21const adopt_lock_t adopt_lock = {}; 22 23mutex::~mutex() 24{ 25 pthread_mutex_destroy(&__m_); 26} 27 28void 29mutex::lock() 30{ 31 int ec = pthread_mutex_lock(&__m_); 32 if (ec) 33 __throw_system_error(ec, "mutex lock failed"); 34} 35 36bool 37mutex::try_lock() _NOEXCEPT 38{ 39 return pthread_mutex_trylock(&__m_) == 0; 40} 41 42void 43mutex::unlock() _NOEXCEPT 44{ 45 int ec = pthread_mutex_unlock(&__m_); 46 (void)ec; 47 assert(ec == 0); 48} 49 50// recursive_mutex 51 52recursive_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; 77fail: 78 __throw_system_error(ec, "recursive_mutex constructor failed"); 79} 80 81recursive_mutex::~recursive_mutex() 82{ 83 int e = pthread_mutex_destroy(&__m_); 84 (void)e; 85 assert(e == 0); 86} 87 88void 89recursive_mutex::lock() 90{ 91 int ec = pthread_mutex_lock(&__m_); 92 if (ec) 93 __throw_system_error(ec, "recursive_mutex lock failed"); 94} 95 96void 97recursive_mutex::unlock() _NOEXCEPT 98{ 99 int e = pthread_mutex_unlock(&__m_); 100 (void)e; 101 assert(e == 0); 102} 103 104bool 105recursive_mutex::try_lock() _NOEXCEPT 106{ 107 return pthread_mutex_trylock(&__m_) == 0; 108} 109 110// timed_mutex 111 112timed_mutex::timed_mutex() 113 : __locked_(false) 114{ 115} 116 117timed_mutex::~timed_mutex() 118{ 119 lock_guard<mutex> _(__m_); 120} 121 122void 123timed_mutex::lock() 124{ 125 unique_lock<mutex> lk(__m_); 126 while (__locked_) 127 __cv_.wait(lk); 128 __locked_ = true; 129} 130 131bool 132timed_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 143void 144timed_mutex::unlock() _NOEXCEPT 145{ 146 lock_guard<mutex> _(__m_); 147 __locked_ = false; 148 __cv_.notify_one(); 149} 150 151// recursive_timed_mutex 152 153recursive_timed_mutex::recursive_timed_mutex() 154 : __count_(0), 155 __id_(0) 156{ 157} 158 159recursive_timed_mutex::~recursive_timed_mutex() 160{ 161 lock_guard<mutex> _(__m_); 162} 163 164void 165recursive_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 182bool 183recursive_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 198void 199recursive_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 219static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; 220static pthread_cond_t cv = PTHREAD_COND_INITIALIZER; 221#endif 222 223void 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