1227825Stheraven//===------------------------- mutex.cpp ----------------------------------===// 2227825Stheraven// 3227825Stheraven// The LLVM Compiler Infrastructure 4227825Stheraven// 5227825Stheraven// This file is dual licensed under the MIT and the University of Illinois Open 6227825Stheraven// Source Licenses. See LICENSE.TXT for details. 7227825Stheraven// 8227825Stheraven//===----------------------------------------------------------------------===// 9227825Stheraven 10241903Sdim#define _LIBCPP_BUILDING_MUTEX 11227825Stheraven#include "mutex" 12227825Stheraven#include "limits" 13227825Stheraven#include "system_error" 14227825Stheraven#include "cassert" 15227825Stheraven 16227825Stheraven_LIBCPP_BEGIN_NAMESPACE_STD 17227825Stheraven 18227825Stheravenconst defer_lock_t defer_lock = {}; 19227825Stheravenconst try_to_lock_t try_to_lock = {}; 20227825Stheravenconst adopt_lock_t adopt_lock = {}; 21227825Stheraven 22227825Stheravenmutex::~mutex() 23227825Stheraven{ 24232950Stheraven pthread_mutex_destroy(&__m_); 25227825Stheraven} 26227825Stheraven 27227825Stheravenvoid 28227825Stheravenmutex::lock() 29227825Stheraven{ 30227825Stheraven int ec = pthread_mutex_lock(&__m_); 31227825Stheraven if (ec) 32227825Stheraven __throw_system_error(ec, "mutex lock failed"); 33227825Stheraven} 34227825Stheraven 35227825Stheravenbool 36241903Sdimmutex::try_lock() _NOEXCEPT 37227825Stheraven{ 38227825Stheraven return pthread_mutex_trylock(&__m_) == 0; 39227825Stheraven} 40227825Stheraven 41227825Stheravenvoid 42241903Sdimmutex::unlock() _NOEXCEPT 43227825Stheraven{ 44227825Stheraven int ec = pthread_mutex_unlock(&__m_); 45262801Sdim (void)ec; 46227825Stheraven assert(ec == 0); 47227825Stheraven} 48227825Stheraven 49227825Stheraven// recursive_mutex 50227825Stheraven 51227825Stheravenrecursive_mutex::recursive_mutex() 52227825Stheraven{ 53227825Stheraven pthread_mutexattr_t attr; 54227825Stheraven int ec = pthread_mutexattr_init(&attr); 55227825Stheraven if (ec) 56227825Stheraven goto fail; 57227825Stheraven ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 58227825Stheraven if (ec) 59227825Stheraven { 60227825Stheraven pthread_mutexattr_destroy(&attr); 61227825Stheraven goto fail; 62227825Stheraven } 63227825Stheraven ec = pthread_mutex_init(&__m_, &attr); 64227825Stheraven if (ec) 65227825Stheraven { 66227825Stheraven pthread_mutexattr_destroy(&attr); 67227825Stheraven goto fail; 68227825Stheraven } 69227825Stheraven ec = pthread_mutexattr_destroy(&attr); 70227825Stheraven if (ec) 71227825Stheraven { 72227825Stheraven pthread_mutex_destroy(&__m_); 73227825Stheraven goto fail; 74227825Stheraven } 75227825Stheraven return; 76227825Stheravenfail: 77227825Stheraven __throw_system_error(ec, "recursive_mutex constructor failed"); 78227825Stheraven} 79227825Stheraven 80227825Stheravenrecursive_mutex::~recursive_mutex() 81227825Stheraven{ 82227825Stheraven int e = pthread_mutex_destroy(&__m_); 83262801Sdim (void)e; 84227825Stheraven assert(e == 0); 85227825Stheraven} 86227825Stheraven 87227825Stheravenvoid 88227825Stheravenrecursive_mutex::lock() 89227825Stheraven{ 90227825Stheraven int ec = pthread_mutex_lock(&__m_); 91227825Stheraven if (ec) 92227825Stheraven __throw_system_error(ec, "recursive_mutex lock failed"); 93227825Stheraven} 94227825Stheraven 95227825Stheravenvoid 96241903Sdimrecursive_mutex::unlock() _NOEXCEPT 97227825Stheraven{ 98227825Stheraven int e = pthread_mutex_unlock(&__m_); 99262801Sdim (void)e; 100227825Stheraven assert(e == 0); 101227825Stheraven} 102227825Stheraven 103227825Stheravenbool 104241903Sdimrecursive_mutex::try_lock() _NOEXCEPT 105227825Stheraven{ 106227825Stheraven return pthread_mutex_trylock(&__m_) == 0; 107227825Stheraven} 108227825Stheraven 109227825Stheraven// timed_mutex 110227825Stheraven 111227825Stheraventimed_mutex::timed_mutex() 112227825Stheraven : __locked_(false) 113227825Stheraven{ 114227825Stheraven} 115227825Stheraven 116227825Stheraventimed_mutex::~timed_mutex() 117227825Stheraven{ 118227825Stheraven lock_guard<mutex> _(__m_); 119227825Stheraven} 120227825Stheraven 121227825Stheravenvoid 122227825Stheraventimed_mutex::lock() 123227825Stheraven{ 124227825Stheraven unique_lock<mutex> lk(__m_); 125227825Stheraven while (__locked_) 126227825Stheraven __cv_.wait(lk); 127227825Stheraven __locked_ = true; 128227825Stheraven} 129227825Stheraven 130227825Stheravenbool 131241903Sdimtimed_mutex::try_lock() _NOEXCEPT 132227825Stheraven{ 133227825Stheraven unique_lock<mutex> lk(__m_, try_to_lock); 134227825Stheraven if (lk.owns_lock() && !__locked_) 135227825Stheraven { 136227825Stheraven __locked_ = true; 137227825Stheraven return true; 138227825Stheraven } 139227825Stheraven return false; 140227825Stheraven} 141227825Stheraven 142227825Stheravenvoid 143241903Sdimtimed_mutex::unlock() _NOEXCEPT 144227825Stheraven{ 145227825Stheraven lock_guard<mutex> _(__m_); 146227825Stheraven __locked_ = false; 147227825Stheraven __cv_.notify_one(); 148227825Stheraven} 149227825Stheraven 150227825Stheraven// recursive_timed_mutex 151227825Stheraven 152227825Stheravenrecursive_timed_mutex::recursive_timed_mutex() 153227825Stheraven : __count_(0), 154227825Stheraven __id_(0) 155227825Stheraven{ 156227825Stheraven} 157227825Stheraven 158227825Stheravenrecursive_timed_mutex::~recursive_timed_mutex() 159227825Stheraven{ 160227825Stheraven lock_guard<mutex> _(__m_); 161227825Stheraven} 162227825Stheraven 163227825Stheravenvoid 164227825Stheravenrecursive_timed_mutex::lock() 165227825Stheraven{ 166227825Stheraven pthread_t id = pthread_self(); 167227825Stheraven unique_lock<mutex> lk(__m_); 168227825Stheraven if (pthread_equal(id, __id_)) 169227825Stheraven { 170227825Stheraven if (__count_ == numeric_limits<size_t>::max()) 171227825Stheraven __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached"); 172227825Stheraven ++__count_; 173227825Stheraven return; 174227825Stheraven } 175227825Stheraven while (__count_ != 0) 176227825Stheraven __cv_.wait(lk); 177227825Stheraven __count_ = 1; 178227825Stheraven __id_ = id; 179227825Stheraven} 180227825Stheraven 181227825Stheravenbool 182241903Sdimrecursive_timed_mutex::try_lock() _NOEXCEPT 183227825Stheraven{ 184227825Stheraven pthread_t id = pthread_self(); 185227825Stheraven unique_lock<mutex> lk(__m_, try_to_lock); 186227825Stheraven if (lk.owns_lock() && (__count_ == 0 || pthread_equal(id, __id_))) 187227825Stheraven { 188227825Stheraven if (__count_ == numeric_limits<size_t>::max()) 189227825Stheraven return false; 190227825Stheraven ++__count_; 191227825Stheraven __id_ = id; 192227825Stheraven return true; 193227825Stheraven } 194227825Stheraven return false; 195227825Stheraven} 196227825Stheraven 197227825Stheravenvoid 198241903Sdimrecursive_timed_mutex::unlock() _NOEXCEPT 199227825Stheraven{ 200227825Stheraven unique_lock<mutex> lk(__m_); 201227825Stheraven if (--__count_ == 0) 202227825Stheraven { 203227825Stheraven __id_ = 0; 204227825Stheraven lk.unlock(); 205227825Stheraven __cv_.notify_one(); 206227825Stheraven } 207227825Stheraven} 208227825Stheraven 209227825Stheraven// If dispatch_once_f ever handles C++ exceptions, and if one can get to it 210227825Stheraven// without illegal macros (unexpected macros not beginning with _UpperCase or 211227825Stheraven// __lowercase), and if it stops spinning waiting threads, then call_once should 212227825Stheraven// call into dispatch_once_f instead of here. Relevant radar this code needs to 213227825Stheraven// keep in sync with: 7741191. 214227825Stheraven 215227825Stheravenstatic pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; 216227825Stheravenstatic pthread_cond_t cv = PTHREAD_COND_INITIALIZER; 217227825Stheraven 218227825Stheravenvoid 219227825Stheraven__call_once(volatile unsigned long& flag, void* arg, void(*func)(void*)) 220227825Stheraven{ 221227825Stheraven pthread_mutex_lock(&mut); 222227825Stheraven while (flag == 1) 223227825Stheraven pthread_cond_wait(&cv, &mut); 224227825Stheraven if (flag == 0) 225227825Stheraven { 226227825Stheraven#ifndef _LIBCPP_NO_EXCEPTIONS 227227825Stheraven try 228227825Stheraven { 229227825Stheraven#endif // _LIBCPP_NO_EXCEPTIONS 230227825Stheraven flag = 1; 231227825Stheraven pthread_mutex_unlock(&mut); 232227825Stheraven func(arg); 233227825Stheraven pthread_mutex_lock(&mut); 234227825Stheraven flag = ~0ul; 235227825Stheraven pthread_mutex_unlock(&mut); 236227825Stheraven pthread_cond_broadcast(&cv); 237227825Stheraven#ifndef _LIBCPP_NO_EXCEPTIONS 238227825Stheraven } 239227825Stheraven catch (...) 240227825Stheraven { 241227825Stheraven pthread_mutex_lock(&mut); 242227825Stheraven flag = 0ul; 243227825Stheraven pthread_mutex_unlock(&mut); 244227825Stheraven pthread_cond_broadcast(&cv); 245227825Stheraven throw; 246227825Stheraven } 247227825Stheraven#endif // _LIBCPP_NO_EXCEPTIONS 248227825Stheraven } 249227825Stheraven else 250227825Stheraven pthread_mutex_unlock(&mut); 251227825Stheraven} 252227825Stheraven 253227825Stheraven_LIBCPP_END_NAMESPACE_STD 254