mutex.cpp revision 285830
1189251Ssam//===------------------------- mutex.cpp ----------------------------------===// 2189251Ssam// 3189251Ssam// The LLVM Compiler Infrastructure 4189251Ssam// 5189251Ssam// This file is dual licensed under the MIT and the University of Illinois Open 6189251Ssam// Source Licenses. See LICENSE.TXT for details. 7189251Ssam// 8189251Ssam//===----------------------------------------------------------------------===// 9189251Ssam 10189251Ssam#define _LIBCPP_BUILDING_MUTEX 11189251Ssam#include "mutex" 12189251Ssam#include "limits" 13189251Ssam#include "system_error" 14189251Ssam#include "cassert" 15189251Ssam 16189251Ssam_LIBCPP_BEGIN_NAMESPACE_STD 17189251Ssam#ifndef _LIBCPP_HAS_NO_THREADS 18189251Ssam 19189251Ssamconst defer_lock_t defer_lock = {}; 20189251Ssamconst try_to_lock_t try_to_lock = {}; 21189251Ssamconst adopt_lock_t adopt_lock = {}; 22189251Ssam 23189251Ssammutex::~mutex() 24189251Ssam{ 25189251Ssam pthread_mutex_destroy(&__m_); 26189251Ssam} 27189251Ssam 28189251Ssamvoid 29189251Ssammutex::lock() 30189251Ssam{ 31189251Ssam int ec = pthread_mutex_lock(&__m_); 32189251Ssam if (ec) 33189251Ssam __throw_system_error(ec, "mutex lock failed"); 34189251Ssam} 35189251Ssam 36189251Ssambool 37189251Ssammutex::try_lock() _NOEXCEPT 38189251Ssam{ 39189251Ssam return pthread_mutex_trylock(&__m_) == 0; 40189251Ssam} 41189251Ssam 42189251Ssamvoid 43189251Ssammutex::unlock() _NOEXCEPT 44189251Ssam{ 45189251Ssam int ec = pthread_mutex_unlock(&__m_); 46189251Ssam (void)ec; 47189251Ssam assert(ec == 0); 48189251Ssam} 49189251Ssam 50189251Ssam// recursive_mutex 51189251Ssam 52189251Ssamrecursive_mutex::recursive_mutex() 53189251Ssam{ 54189251Ssam pthread_mutexattr_t attr; 55189251Ssam int ec = pthread_mutexattr_init(&attr); 56189251Ssam if (ec) 57189251Ssam goto fail; 58189251Ssam ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 59189251Ssam if (ec) 60189251Ssam { 61189251Ssam pthread_mutexattr_destroy(&attr); 62189251Ssam goto fail; 63189251Ssam } 64189251Ssam ec = pthread_mutex_init(&__m_, &attr); 65189251Ssam if (ec) 66189251Ssam { 67189251Ssam pthread_mutexattr_destroy(&attr); 68189251Ssam goto fail; 69189251Ssam } 70189251Ssam ec = pthread_mutexattr_destroy(&attr); 71189251Ssam if (ec) 72189251Ssam { 73189251Ssam pthread_mutex_destroy(&__m_); 74189251Ssam goto fail; 75189251Ssam } 76189251Ssam return; 77189251Ssamfail: 78189251Ssam __throw_system_error(ec, "recursive_mutex constructor failed"); 79189251Ssam} 80189251Ssam 81189251Ssamrecursive_mutex::~recursive_mutex() 82189251Ssam{ 83189251Ssam int e = pthread_mutex_destroy(&__m_); 84189251Ssam (void)e; 85189251Ssam assert(e == 0); 86189251Ssam} 87189251Ssam 88189251Ssamvoid 89189251Ssamrecursive_mutex::lock() 90189251Ssam{ 91189251Ssam int ec = pthread_mutex_lock(&__m_); 92189251Ssam if (ec) 93189251Ssam __throw_system_error(ec, "recursive_mutex lock failed"); 94189251Ssam} 95189251Ssam 96189251Ssamvoid 97189251Ssamrecursive_mutex::unlock() _NOEXCEPT 98189251Ssam{ 99189251Ssam int e = pthread_mutex_unlock(&__m_); 100189251Ssam (void)e; 101189251Ssam assert(e == 0); 102189251Ssam} 103189251Ssam 104189251Ssambool 105189251Ssamrecursive_mutex::try_lock() _NOEXCEPT 106189251Ssam{ 107189251Ssam return pthread_mutex_trylock(&__m_) == 0; 108189251Ssam} 109189251Ssam 110189251Ssam// timed_mutex 111189251Ssam 112189251Ssamtimed_mutex::timed_mutex() 113189251Ssam : __locked_(false) 114189251Ssam{ 115189251Ssam} 116189251Ssam 117189251Ssamtimed_mutex::~timed_mutex() 118189251Ssam{ 119189251Ssam lock_guard<mutex> _(__m_); 120189251Ssam} 121189251Ssam 122189251Ssamvoid 123189251Ssamtimed_mutex::lock() 124189251Ssam{ 125189251Ssam unique_lock<mutex> lk(__m_); 126189251Ssam while (__locked_) 127189251Ssam __cv_.wait(lk); 128189251Ssam __locked_ = true; 129189251Ssam} 130189251Ssam 131189251Ssambool 132189251Ssamtimed_mutex::try_lock() _NOEXCEPT 133189251Ssam{ 134189251Ssam unique_lock<mutex> lk(__m_, try_to_lock); 135189251Ssam if (lk.owns_lock() && !__locked_) 136189251Ssam { 137189251Ssam __locked_ = true; 138189251Ssam return true; 139189251Ssam } 140189251Ssam return false; 141189251Ssam} 142189251Ssam 143189251Ssamvoid 144189251Ssamtimed_mutex::unlock() _NOEXCEPT 145189251Ssam{ 146189251Ssam lock_guard<mutex> _(__m_); 147189251Ssam __locked_ = false; 148189251Ssam __cv_.notify_one(); 149189251Ssam} 150189251Ssam 151189251Ssam// recursive_timed_mutex 152189251Ssam 153189251Ssamrecursive_timed_mutex::recursive_timed_mutex() 154189251Ssam : __count_(0), 155189251Ssam __id_(0) 156189251Ssam{ 157189251Ssam} 158189251Ssam 159189251Ssamrecursive_timed_mutex::~recursive_timed_mutex() 160189251Ssam{ 161189251Ssam lock_guard<mutex> _(__m_); 162189251Ssam} 163189251Ssam 164189251Ssamvoid 165189251Ssamrecursive_timed_mutex::lock() 166189251Ssam{ 167189251Ssam pthread_t id = pthread_self(); 168189251Ssam unique_lock<mutex> lk(__m_); 169189251Ssam if (pthread_equal(id, __id_)) 170189251Ssam { 171189251Ssam if (__count_ == numeric_limits<size_t>::max()) 172189251Ssam __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached"); 173189251Ssam ++__count_; 174189251Ssam return; 175189251Ssam } 176189251Ssam while (__count_ != 0) 177189251Ssam __cv_.wait(lk); 178189251Ssam __count_ = 1; 179189251Ssam __id_ = id; 180189251Ssam} 181189251Ssam 182189251Ssambool 183189251Ssamrecursive_timed_mutex::try_lock() _NOEXCEPT 184189251Ssam{ 185189251Ssam pthread_t id = pthread_self(); 186189251Ssam unique_lock<mutex> lk(__m_, try_to_lock); 187189251Ssam if (lk.owns_lock() && (__count_ == 0 || pthread_equal(id, __id_))) 188189251Ssam { 189189251Ssam if (__count_ == numeric_limits<size_t>::max()) 190189251Ssam return false; 191189251Ssam ++__count_; 192189251Ssam __id_ = id; 193189251Ssam return true; 194189251Ssam } 195189251Ssam return false; 196189251Ssam} 197189251Ssam 198189251Ssamvoid 199189251Ssamrecursive_timed_mutex::unlock() _NOEXCEPT 200189251Ssam{ 201189251Ssam unique_lock<mutex> lk(__m_); 202189251Ssam if (--__count_ == 0) 203189251Ssam { 204189251Ssam __id_ = 0; 205189251Ssam lk.unlock(); 206189251Ssam __cv_.notify_one(); 207189251Ssam } 208189251Ssam} 209189251Ssam 210189251Ssam#endif // !_LIBCPP_HAS_NO_THREADS 211189251Ssam 212189251Ssam// If dispatch_once_f ever handles C++ exceptions, and if one can get to it 213189251Ssam// without illegal macros (unexpected macros not beginning with _UpperCase or 214189251Ssam// __lowercase), and if it stops spinning waiting threads, then call_once should 215189251Ssam// call into dispatch_once_f instead of here. Relevant radar this code needs to 216189251Ssam// keep in sync with: 7741191. 217189251Ssam 218189251Ssam#ifndef _LIBCPP_HAS_NO_THREADS 219189251Ssamstatic pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; 220189251Ssamstatic pthread_cond_t cv = PTHREAD_COND_INITIALIZER; 221189251Ssam#endif 222189251Ssam 223189251Ssamvoid 224189251Ssam__call_once(volatile unsigned long& flag, void* arg, void(*func)(void*)) 225189251Ssam{ 226189251Ssam#if defined(_LIBCPP_HAS_NO_THREADS) 227189251Ssam if (flag == 0) 228189251Ssam { 229189251Ssam#ifndef _LIBCPP_NO_EXCEPTIONS 230189251Ssam try 231189251Ssam { 232189251Ssam#endif // _LIBCPP_NO_EXCEPTIONS 233189251Ssam flag = 1; 234189251Ssam func(arg); 235189251Ssam flag = ~0ul; 236189251Ssam#ifndef _LIBCPP_NO_EXCEPTIONS 237189251Ssam } 238189251Ssam catch (...) 239189251Ssam { 240189251Ssam flag = 0ul; 241189251Ssam throw; 242189251Ssam } 243189251Ssam#endif // _LIBCPP_NO_EXCEPTIONS 244189251Ssam } 245189251Ssam#else // !_LIBCPP_HAS_NO_THREADS 246189251Ssam pthread_mutex_lock(&mut); 247189251Ssam while (flag == 1) 248189251Ssam pthread_cond_wait(&cv, &mut); 249189251Ssam if (flag == 0) 250189251Ssam { 251189251Ssam#ifndef _LIBCPP_NO_EXCEPTIONS 252189251Ssam try 253189251Ssam { 254189251Ssam#endif // _LIBCPP_NO_EXCEPTIONS 255189251Ssam flag = 1; 256189251Ssam pthread_mutex_unlock(&mut); 257189251Ssam func(arg); 258189251Ssam pthread_mutex_lock(&mut); 259189251Ssam flag = ~0ul; 260189251Ssam pthread_mutex_unlock(&mut); 261189251Ssam pthread_cond_broadcast(&cv); 262189251Ssam#ifndef _LIBCPP_NO_EXCEPTIONS 263189251Ssam } 264189251Ssam catch (...) 265189251Ssam { 266189251Ssam pthread_mutex_lock(&mut); 267189251Ssam flag = 0ul; 268189251Ssam pthread_mutex_unlock(&mut); 269189251Ssam pthread_cond_broadcast(&cv); 270189251Ssam throw; 271189251Ssam } 272189251Ssam#endif // _LIBCPP_NO_EXCEPTIONS 273189251Ssam } 274189251Ssam else 275189251Ssam pthread_mutex_unlock(&mut); 276189251Ssam#endif // !_LIBCPP_HAS_NO_THREADS 277189251Ssam 278189251Ssam} 279189251Ssam 280189251Ssam_LIBCPP_END_NAMESPACE_STD 281189251Ssam