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