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