14684ddb6SLionel Sambuc //===------------------------- mutex.cpp ----------------------------------===//
24684ddb6SLionel Sambuc //
34684ddb6SLionel Sambuc // The LLVM Compiler Infrastructure
44684ddb6SLionel Sambuc //
54684ddb6SLionel Sambuc // This file is dual licensed under the MIT and the University of Illinois Open
64684ddb6SLionel Sambuc // Source Licenses. See LICENSE.TXT for details.
74684ddb6SLionel Sambuc //
84684ddb6SLionel Sambuc //===----------------------------------------------------------------------===//
94684ddb6SLionel Sambuc
104684ddb6SLionel Sambuc #define _LIBCPP_BUILDING_MUTEX
114684ddb6SLionel Sambuc #include "mutex"
124684ddb6SLionel Sambuc #include "limits"
134684ddb6SLionel Sambuc #include "system_error"
144684ddb6SLionel Sambuc #include "cassert"
15*0a6a1f1dSLionel Sambuc #include "include/atomic_support.h"
164684ddb6SLionel Sambuc
174684ddb6SLionel Sambuc _LIBCPP_BEGIN_NAMESPACE_STD
18*0a6a1f1dSLionel Sambuc #ifndef _LIBCPP_HAS_NO_THREADS
194684ddb6SLionel Sambuc
204684ddb6SLionel Sambuc const defer_lock_t defer_lock = {};
214684ddb6SLionel Sambuc const try_to_lock_t try_to_lock = {};
224684ddb6SLionel Sambuc const adopt_lock_t adopt_lock = {};
234684ddb6SLionel Sambuc
~mutex()244684ddb6SLionel Sambuc mutex::~mutex()
254684ddb6SLionel Sambuc {
264684ddb6SLionel Sambuc pthread_mutex_destroy(&__m_);
274684ddb6SLionel Sambuc }
284684ddb6SLionel Sambuc
294684ddb6SLionel Sambuc void
lock()304684ddb6SLionel Sambuc mutex::lock()
314684ddb6SLionel Sambuc {
324684ddb6SLionel Sambuc int ec = pthread_mutex_lock(&__m_);
334684ddb6SLionel Sambuc if (ec)
344684ddb6SLionel Sambuc __throw_system_error(ec, "mutex lock failed");
354684ddb6SLionel Sambuc }
364684ddb6SLionel Sambuc
374684ddb6SLionel Sambuc bool
try_lock()384684ddb6SLionel Sambuc mutex::try_lock() _NOEXCEPT
394684ddb6SLionel Sambuc {
404684ddb6SLionel Sambuc return pthread_mutex_trylock(&__m_) == 0;
414684ddb6SLionel Sambuc }
424684ddb6SLionel Sambuc
434684ddb6SLionel Sambuc void
unlock()444684ddb6SLionel Sambuc mutex::unlock() _NOEXCEPT
454684ddb6SLionel Sambuc {
464684ddb6SLionel Sambuc int ec = pthread_mutex_unlock(&__m_);
474684ddb6SLionel Sambuc (void)ec;
484684ddb6SLionel Sambuc assert(ec == 0);
494684ddb6SLionel Sambuc }
504684ddb6SLionel Sambuc
514684ddb6SLionel Sambuc // recursive_mutex
524684ddb6SLionel Sambuc
recursive_mutex()534684ddb6SLionel Sambuc recursive_mutex::recursive_mutex()
544684ddb6SLionel Sambuc {
554684ddb6SLionel Sambuc pthread_mutexattr_t attr;
564684ddb6SLionel Sambuc int ec = pthread_mutexattr_init(&attr);
574684ddb6SLionel Sambuc if (ec)
584684ddb6SLionel Sambuc goto fail;
594684ddb6SLionel Sambuc ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
604684ddb6SLionel Sambuc if (ec)
614684ddb6SLionel Sambuc {
624684ddb6SLionel Sambuc pthread_mutexattr_destroy(&attr);
634684ddb6SLionel Sambuc goto fail;
644684ddb6SLionel Sambuc }
654684ddb6SLionel Sambuc ec = pthread_mutex_init(&__m_, &attr);
664684ddb6SLionel Sambuc if (ec)
674684ddb6SLionel Sambuc {
684684ddb6SLionel Sambuc pthread_mutexattr_destroy(&attr);
694684ddb6SLionel Sambuc goto fail;
704684ddb6SLionel Sambuc }
714684ddb6SLionel Sambuc ec = pthread_mutexattr_destroy(&attr);
724684ddb6SLionel Sambuc if (ec)
734684ddb6SLionel Sambuc {
744684ddb6SLionel Sambuc pthread_mutex_destroy(&__m_);
754684ddb6SLionel Sambuc goto fail;
764684ddb6SLionel Sambuc }
774684ddb6SLionel Sambuc return;
784684ddb6SLionel Sambuc fail:
794684ddb6SLionel Sambuc __throw_system_error(ec, "recursive_mutex constructor failed");
804684ddb6SLionel Sambuc }
814684ddb6SLionel Sambuc
~recursive_mutex()824684ddb6SLionel Sambuc recursive_mutex::~recursive_mutex()
834684ddb6SLionel Sambuc {
844684ddb6SLionel Sambuc int e = pthread_mutex_destroy(&__m_);
854684ddb6SLionel Sambuc (void)e;
864684ddb6SLionel Sambuc assert(e == 0);
874684ddb6SLionel Sambuc }
884684ddb6SLionel Sambuc
894684ddb6SLionel Sambuc void
lock()904684ddb6SLionel Sambuc recursive_mutex::lock()
914684ddb6SLionel Sambuc {
924684ddb6SLionel Sambuc int ec = pthread_mutex_lock(&__m_);
934684ddb6SLionel Sambuc if (ec)
944684ddb6SLionel Sambuc __throw_system_error(ec, "recursive_mutex lock failed");
954684ddb6SLionel Sambuc }
964684ddb6SLionel Sambuc
974684ddb6SLionel Sambuc void
unlock()984684ddb6SLionel Sambuc recursive_mutex::unlock() _NOEXCEPT
994684ddb6SLionel Sambuc {
1004684ddb6SLionel Sambuc int e = pthread_mutex_unlock(&__m_);
1014684ddb6SLionel Sambuc (void)e;
1024684ddb6SLionel Sambuc assert(e == 0);
1034684ddb6SLionel Sambuc }
1044684ddb6SLionel Sambuc
1054684ddb6SLionel Sambuc bool
try_lock()1064684ddb6SLionel Sambuc recursive_mutex::try_lock() _NOEXCEPT
1074684ddb6SLionel Sambuc {
1084684ddb6SLionel Sambuc return pthread_mutex_trylock(&__m_) == 0;
1094684ddb6SLionel Sambuc }
1104684ddb6SLionel Sambuc
1114684ddb6SLionel Sambuc // timed_mutex
1124684ddb6SLionel Sambuc
timed_mutex()1134684ddb6SLionel Sambuc timed_mutex::timed_mutex()
1144684ddb6SLionel Sambuc : __locked_(false)
1154684ddb6SLionel Sambuc {
1164684ddb6SLionel Sambuc }
1174684ddb6SLionel Sambuc
~timed_mutex()1184684ddb6SLionel Sambuc timed_mutex::~timed_mutex()
1194684ddb6SLionel Sambuc {
1204684ddb6SLionel Sambuc lock_guard<mutex> _(__m_);
1214684ddb6SLionel Sambuc }
1224684ddb6SLionel Sambuc
1234684ddb6SLionel Sambuc void
lock()1244684ddb6SLionel Sambuc timed_mutex::lock()
1254684ddb6SLionel Sambuc {
1264684ddb6SLionel Sambuc unique_lock<mutex> lk(__m_);
1274684ddb6SLionel Sambuc while (__locked_)
1284684ddb6SLionel Sambuc __cv_.wait(lk);
1294684ddb6SLionel Sambuc __locked_ = true;
1304684ddb6SLionel Sambuc }
1314684ddb6SLionel Sambuc
1324684ddb6SLionel Sambuc bool
try_lock()1334684ddb6SLionel Sambuc timed_mutex::try_lock() _NOEXCEPT
1344684ddb6SLionel Sambuc {
1354684ddb6SLionel Sambuc unique_lock<mutex> lk(__m_, try_to_lock);
1364684ddb6SLionel Sambuc if (lk.owns_lock() && !__locked_)
1374684ddb6SLionel Sambuc {
1384684ddb6SLionel Sambuc __locked_ = true;
1394684ddb6SLionel Sambuc return true;
1404684ddb6SLionel Sambuc }
1414684ddb6SLionel Sambuc return false;
1424684ddb6SLionel Sambuc }
1434684ddb6SLionel Sambuc
1444684ddb6SLionel Sambuc void
unlock()1454684ddb6SLionel Sambuc timed_mutex::unlock() _NOEXCEPT
1464684ddb6SLionel Sambuc {
1474684ddb6SLionel Sambuc lock_guard<mutex> _(__m_);
1484684ddb6SLionel Sambuc __locked_ = false;
1494684ddb6SLionel Sambuc __cv_.notify_one();
1504684ddb6SLionel Sambuc }
1514684ddb6SLionel Sambuc
1524684ddb6SLionel Sambuc // recursive_timed_mutex
1534684ddb6SLionel Sambuc
recursive_timed_mutex()1544684ddb6SLionel Sambuc recursive_timed_mutex::recursive_timed_mutex()
1554684ddb6SLionel Sambuc : __count_(0),
1564684ddb6SLionel Sambuc __id_(0)
1574684ddb6SLionel Sambuc {
1584684ddb6SLionel Sambuc }
1594684ddb6SLionel Sambuc
~recursive_timed_mutex()1604684ddb6SLionel Sambuc recursive_timed_mutex::~recursive_timed_mutex()
1614684ddb6SLionel Sambuc {
1624684ddb6SLionel Sambuc lock_guard<mutex> _(__m_);
1634684ddb6SLionel Sambuc }
1644684ddb6SLionel Sambuc
1654684ddb6SLionel Sambuc void
lock()1664684ddb6SLionel Sambuc recursive_timed_mutex::lock()
1674684ddb6SLionel Sambuc {
1684684ddb6SLionel Sambuc pthread_t id = pthread_self();
1694684ddb6SLionel Sambuc unique_lock<mutex> lk(__m_);
1704684ddb6SLionel Sambuc if (pthread_equal(id, __id_))
1714684ddb6SLionel Sambuc {
1724684ddb6SLionel Sambuc if (__count_ == numeric_limits<size_t>::max())
1734684ddb6SLionel Sambuc __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached");
1744684ddb6SLionel Sambuc ++__count_;
1754684ddb6SLionel Sambuc return;
1764684ddb6SLionel Sambuc }
1774684ddb6SLionel Sambuc while (__count_ != 0)
1784684ddb6SLionel Sambuc __cv_.wait(lk);
1794684ddb6SLionel Sambuc __count_ = 1;
1804684ddb6SLionel Sambuc __id_ = id;
1814684ddb6SLionel Sambuc }
1824684ddb6SLionel Sambuc
1834684ddb6SLionel Sambuc bool
try_lock()1844684ddb6SLionel Sambuc recursive_timed_mutex::try_lock() _NOEXCEPT
1854684ddb6SLionel Sambuc {
1864684ddb6SLionel Sambuc pthread_t id = pthread_self();
1874684ddb6SLionel Sambuc unique_lock<mutex> lk(__m_, try_to_lock);
1884684ddb6SLionel Sambuc if (lk.owns_lock() && (__count_ == 0 || pthread_equal(id, __id_)))
1894684ddb6SLionel Sambuc {
1904684ddb6SLionel Sambuc if (__count_ == numeric_limits<size_t>::max())
1914684ddb6SLionel Sambuc return false;
1924684ddb6SLionel Sambuc ++__count_;
1934684ddb6SLionel Sambuc __id_ = id;
1944684ddb6SLionel Sambuc return true;
1954684ddb6SLionel Sambuc }
1964684ddb6SLionel Sambuc return false;
1974684ddb6SLionel Sambuc }
1984684ddb6SLionel Sambuc
1994684ddb6SLionel Sambuc void
unlock()2004684ddb6SLionel Sambuc recursive_timed_mutex::unlock() _NOEXCEPT
2014684ddb6SLionel Sambuc {
2024684ddb6SLionel Sambuc unique_lock<mutex> lk(__m_);
2034684ddb6SLionel Sambuc if (--__count_ == 0)
2044684ddb6SLionel Sambuc {
2054684ddb6SLionel Sambuc __id_ = 0;
2064684ddb6SLionel Sambuc lk.unlock();
2074684ddb6SLionel Sambuc __cv_.notify_one();
2084684ddb6SLionel Sambuc }
2094684ddb6SLionel Sambuc }
2104684ddb6SLionel Sambuc
211*0a6a1f1dSLionel Sambuc #endif // !_LIBCPP_HAS_NO_THREADS
212*0a6a1f1dSLionel Sambuc
2134684ddb6SLionel Sambuc // If dispatch_once_f ever handles C++ exceptions, and if one can get to it
2144684ddb6SLionel Sambuc // without illegal macros (unexpected macros not beginning with _UpperCase or
2154684ddb6SLionel Sambuc // __lowercase), and if it stops spinning waiting threads, then call_once should
2164684ddb6SLionel Sambuc // call into dispatch_once_f instead of here. Relevant radar this code needs to
2174684ddb6SLionel Sambuc // keep in sync with: 7741191.
2184684ddb6SLionel Sambuc
219*0a6a1f1dSLionel Sambuc #ifndef _LIBCPP_HAS_NO_THREADS
2204684ddb6SLionel Sambuc static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
2214684ddb6SLionel Sambuc static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
222*0a6a1f1dSLionel Sambuc #endif
2234684ddb6SLionel Sambuc
224*0a6a1f1dSLionel Sambuc /// NOTE: Changes to flag are done via relaxed atomic stores
225*0a6a1f1dSLionel Sambuc /// even though the accesses are protected by a mutex because threads
226*0a6a1f1dSLionel Sambuc /// just entering 'call_once` concurrently read from flag.
2274684ddb6SLionel Sambuc void
__call_once(volatile unsigned long & flag,void * arg,void (* func)(void *))2284684ddb6SLionel Sambuc __call_once(volatile unsigned long& flag, void* arg, void(*func)(void*))
2294684ddb6SLionel Sambuc {
230*0a6a1f1dSLionel Sambuc #if defined(_LIBCPP_HAS_NO_THREADS)
231*0a6a1f1dSLionel Sambuc if (flag == 0)
232*0a6a1f1dSLionel Sambuc {
233*0a6a1f1dSLionel Sambuc #ifndef _LIBCPP_NO_EXCEPTIONS
234*0a6a1f1dSLionel Sambuc try
235*0a6a1f1dSLionel Sambuc {
236*0a6a1f1dSLionel Sambuc #endif // _LIBCPP_NO_EXCEPTIONS
237*0a6a1f1dSLionel Sambuc flag = 1;
238*0a6a1f1dSLionel Sambuc func(arg);
239*0a6a1f1dSLionel Sambuc flag = ~0ul;
240*0a6a1f1dSLionel Sambuc #ifndef _LIBCPP_NO_EXCEPTIONS
241*0a6a1f1dSLionel Sambuc }
242*0a6a1f1dSLionel Sambuc catch (...)
243*0a6a1f1dSLionel Sambuc {
244*0a6a1f1dSLionel Sambuc flag = 0ul;
245*0a6a1f1dSLionel Sambuc throw;
246*0a6a1f1dSLionel Sambuc }
247*0a6a1f1dSLionel Sambuc #endif // _LIBCPP_NO_EXCEPTIONS
248*0a6a1f1dSLionel Sambuc }
249*0a6a1f1dSLionel Sambuc #else // !_LIBCPP_HAS_NO_THREADS
2504684ddb6SLionel Sambuc pthread_mutex_lock(&mut);
2514684ddb6SLionel Sambuc while (flag == 1)
2524684ddb6SLionel Sambuc pthread_cond_wait(&cv, &mut);
2534684ddb6SLionel Sambuc if (flag == 0)
2544684ddb6SLionel Sambuc {
2554684ddb6SLionel Sambuc #ifndef _LIBCPP_NO_EXCEPTIONS
2564684ddb6SLionel Sambuc try
2574684ddb6SLionel Sambuc {
2584684ddb6SLionel Sambuc #endif // _LIBCPP_NO_EXCEPTIONS
259*0a6a1f1dSLionel Sambuc __libcpp_relaxed_store(&flag, 1ul);
2604684ddb6SLionel Sambuc pthread_mutex_unlock(&mut);
2614684ddb6SLionel Sambuc func(arg);
2624684ddb6SLionel Sambuc pthread_mutex_lock(&mut);
263*0a6a1f1dSLionel Sambuc __libcpp_relaxed_store(&flag, ~0ul);
2644684ddb6SLionel Sambuc pthread_mutex_unlock(&mut);
2654684ddb6SLionel Sambuc pthread_cond_broadcast(&cv);
2664684ddb6SLionel Sambuc #ifndef _LIBCPP_NO_EXCEPTIONS
2674684ddb6SLionel Sambuc }
2684684ddb6SLionel Sambuc catch (...)
2694684ddb6SLionel Sambuc {
2704684ddb6SLionel Sambuc pthread_mutex_lock(&mut);
271*0a6a1f1dSLionel Sambuc __libcpp_relaxed_store(&flag, 0ul);
2724684ddb6SLionel Sambuc pthread_mutex_unlock(&mut);
2734684ddb6SLionel Sambuc pthread_cond_broadcast(&cv);
2744684ddb6SLionel Sambuc throw;
2754684ddb6SLionel Sambuc }
2764684ddb6SLionel Sambuc #endif // _LIBCPP_NO_EXCEPTIONS
2774684ddb6SLionel Sambuc }
2784684ddb6SLionel Sambuc else
2794684ddb6SLionel Sambuc pthread_mutex_unlock(&mut);
280*0a6a1f1dSLionel Sambuc #endif // !_LIBCPP_HAS_NO_THREADS
281*0a6a1f1dSLionel Sambuc
2824684ddb6SLionel Sambuc }
2834684ddb6SLionel Sambuc
2844684ddb6SLionel Sambuc _LIBCPP_END_NAMESPACE_STD
285