1eb8650a7SLouis Dionne //===----------------------------------------------------------------------===//
23e519524SHoward Hinnant //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63e519524SHoward Hinnant //
73e519524SHoward Hinnant //===----------------------------------------------------------------------===//
83e519524SHoward Hinnant
9*f87aa19bSLouis Dionne #include <__assert>
10bbb0f2c7SArthur O'Dwyer #include <limits>
11bbb0f2c7SArthur O'Dwyer #include <mutex>
12bbb0f2c7SArthur O'Dwyer #include <system_error>
13bbb0f2c7SArthur O'Dwyer
14e8fd1645SEric Fiselier #include "include/atomic_support.h"
153e519524SHoward Hinnant
16996e62eeSPetr Hosek #ifndef _LIBCPP_HAS_NO_THREADS
17a9b5fff5SMichał Górny # if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
18996e62eeSPetr Hosek # pragma comment(lib, "pthread")
19996e62eeSPetr Hosek # endif
20996e62eeSPetr Hosek #endif
21996e62eeSPetr Hosek
22bbb0f2c7SArthur O'Dwyer _LIBCPP_PUSH_MACROS
23bbb0f2c7SArthur O'Dwyer #include <__undef_macros>
24bbb0f2c7SArthur O'Dwyer
253e519524SHoward Hinnant _LIBCPP_BEGIN_NAMESPACE_STD
26bbb0f2c7SArthur O'Dwyer
27b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
283e519524SHoward Hinnant
29e16f2cb6SLouis Dionne const defer_lock_t defer_lock{};
30e16f2cb6SLouis Dionne const try_to_lock_t try_to_lock{};
31e16f2cb6SLouis Dionne const adopt_lock_t adopt_lock{};
323e519524SHoward Hinnant
338baf8383SEric Fiselier // ~mutex is defined elsewhere
343e519524SHoward Hinnant
353e519524SHoward Hinnant void
lock()363e519524SHoward Hinnant mutex::lock()
373e519524SHoward Hinnant {
38c7e4239fSAsiri Rathnayake int ec = __libcpp_mutex_lock(&__m_);
393e519524SHoward Hinnant if (ec)
403e519524SHoward Hinnant __throw_system_error(ec, "mutex lock failed");
413e519524SHoward Hinnant }
423e519524SHoward Hinnant
433e519524SHoward Hinnant bool
try_lock()445601305fSLouis Dionne mutex::try_lock() noexcept
453e519524SHoward Hinnant {
4608e1477cSEric Fiselier return __libcpp_mutex_trylock(&__m_);
473e519524SHoward Hinnant }
483e519524SHoward Hinnant
493e519524SHoward Hinnant void
unlock()505601305fSLouis Dionne mutex::unlock() noexcept
513e519524SHoward Hinnant {
52c7e4239fSAsiri Rathnayake int ec = __libcpp_mutex_unlock(&__m_);
5312bfc4feSHoward Hinnant (void)ec;
54e49cdfbeSEric Fiselier _LIBCPP_ASSERT(ec == 0, "call to mutex::unlock failed");
553e519524SHoward Hinnant }
563e519524SHoward Hinnant
573e519524SHoward Hinnant // recursive_mutex
583e519524SHoward Hinnant
recursive_mutex()593e519524SHoward Hinnant recursive_mutex::recursive_mutex()
603e519524SHoward Hinnant {
61c7e4239fSAsiri Rathnayake int ec = __libcpp_recursive_mutex_init(&__m_);
623e519524SHoward Hinnant if (ec)
633e519524SHoward Hinnant __throw_system_error(ec, "recursive_mutex constructor failed");
643e519524SHoward Hinnant }
653e519524SHoward Hinnant
~recursive_mutex()663e519524SHoward Hinnant recursive_mutex::~recursive_mutex()
673e519524SHoward Hinnant {
6858a0dceeSSaleem Abdulrasool int e = __libcpp_recursive_mutex_destroy(&__m_);
6912bfc4feSHoward Hinnant (void)e;
70e49cdfbeSEric Fiselier _LIBCPP_ASSERT(e == 0, "call to ~recursive_mutex() failed");
713e519524SHoward Hinnant }
723e519524SHoward Hinnant
733e519524SHoward Hinnant void
lock()743e519524SHoward Hinnant recursive_mutex::lock()
753e519524SHoward Hinnant {
7658a0dceeSSaleem Abdulrasool int ec = __libcpp_recursive_mutex_lock(&__m_);
773e519524SHoward Hinnant if (ec)
783e519524SHoward Hinnant __throw_system_error(ec, "recursive_mutex lock failed");
793e519524SHoward Hinnant }
803e519524SHoward Hinnant
813e519524SHoward Hinnant void
unlock()825601305fSLouis Dionne recursive_mutex::unlock() noexcept
833e519524SHoward Hinnant {
8458a0dceeSSaleem Abdulrasool int e = __libcpp_recursive_mutex_unlock(&__m_);
8512bfc4feSHoward Hinnant (void)e;
86e49cdfbeSEric Fiselier _LIBCPP_ASSERT(e == 0, "call to recursive_mutex::unlock() failed");
873e519524SHoward Hinnant }
883e519524SHoward Hinnant
893e519524SHoward Hinnant bool
try_lock()905601305fSLouis Dionne recursive_mutex::try_lock() noexcept
913e519524SHoward Hinnant {
9208e1477cSEric Fiselier return __libcpp_recursive_mutex_trylock(&__m_);
933e519524SHoward Hinnant }
943e519524SHoward Hinnant
953e519524SHoward Hinnant // timed_mutex
963e519524SHoward Hinnant
timed_mutex()973e519524SHoward Hinnant timed_mutex::timed_mutex()
983e519524SHoward Hinnant : __locked_(false)
993e519524SHoward Hinnant {
1003e519524SHoward Hinnant }
1013e519524SHoward Hinnant
~timed_mutex()1023e519524SHoward Hinnant timed_mutex::~timed_mutex()
1033e519524SHoward Hinnant {
1043e519524SHoward Hinnant lock_guard<mutex> _(__m_);
1053e519524SHoward Hinnant }
1063e519524SHoward Hinnant
1073e519524SHoward Hinnant void
lock()1083e519524SHoward Hinnant timed_mutex::lock()
1093e519524SHoward Hinnant {
1103e519524SHoward Hinnant unique_lock<mutex> lk(__m_);
1113e519524SHoward Hinnant while (__locked_)
1123e519524SHoward Hinnant __cv_.wait(lk);
1133e519524SHoward Hinnant __locked_ = true;
1143e519524SHoward Hinnant }
1153e519524SHoward Hinnant
1163e519524SHoward Hinnant bool
try_lock()1175601305fSLouis Dionne timed_mutex::try_lock() noexcept
1183e519524SHoward Hinnant {
1193e519524SHoward Hinnant unique_lock<mutex> lk(__m_, try_to_lock);
1203e519524SHoward Hinnant if (lk.owns_lock() && !__locked_)
1213e519524SHoward Hinnant {
1223e519524SHoward Hinnant __locked_ = true;
1233e519524SHoward Hinnant return true;
1243e519524SHoward Hinnant }
1253e519524SHoward Hinnant return false;
1263e519524SHoward Hinnant }
1273e519524SHoward Hinnant
1283e519524SHoward Hinnant void
unlock()1295601305fSLouis Dionne timed_mutex::unlock() noexcept
1303e519524SHoward Hinnant {
1313e519524SHoward Hinnant lock_guard<mutex> _(__m_);
1323e519524SHoward Hinnant __locked_ = false;
1333e519524SHoward Hinnant __cv_.notify_one();
1343e519524SHoward Hinnant }
1353e519524SHoward Hinnant
1363e519524SHoward Hinnant // recursive_timed_mutex
1373e519524SHoward Hinnant
recursive_timed_mutex()1383e519524SHoward Hinnant recursive_timed_mutex::recursive_timed_mutex()
1393e519524SHoward Hinnant : __count_(0),
1402b1d4254SMarshall Clow __id_{}
1413e519524SHoward Hinnant {
1423e519524SHoward Hinnant }
1433e519524SHoward Hinnant
~recursive_timed_mutex()1443e519524SHoward Hinnant recursive_timed_mutex::~recursive_timed_mutex()
1453e519524SHoward Hinnant {
1463e519524SHoward Hinnant lock_guard<mutex> _(__m_);
1473e519524SHoward Hinnant }
1483e519524SHoward Hinnant
1493e519524SHoward Hinnant void
lock()1503e519524SHoward Hinnant recursive_timed_mutex::lock()
1513e519524SHoward Hinnant {
1522b1d4254SMarshall Clow __thread_id id = this_thread::get_id();
1533e519524SHoward Hinnant unique_lock<mutex> lk(__m_);
1542b1d4254SMarshall Clow if (id ==__id_)
1553e519524SHoward Hinnant {
1563e519524SHoward Hinnant if (__count_ == numeric_limits<size_t>::max())
1573e519524SHoward Hinnant __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached");
1583e519524SHoward Hinnant ++__count_;
1593e519524SHoward Hinnant return;
1603e519524SHoward Hinnant }
1613e519524SHoward Hinnant while (__count_ != 0)
1623e519524SHoward Hinnant __cv_.wait(lk);
1633e519524SHoward Hinnant __count_ = 1;
1643e519524SHoward Hinnant __id_ = id;
1653e519524SHoward Hinnant }
1663e519524SHoward Hinnant
1673e519524SHoward Hinnant bool
try_lock()1685601305fSLouis Dionne recursive_timed_mutex::try_lock() noexcept
1693e519524SHoward Hinnant {
1702b1d4254SMarshall Clow __thread_id id = this_thread::get_id();
1713e519524SHoward Hinnant unique_lock<mutex> lk(__m_, try_to_lock);
1722b1d4254SMarshall Clow if (lk.owns_lock() && (__count_ == 0 || id == __id_))
1733e519524SHoward Hinnant {
1743e519524SHoward Hinnant if (__count_ == numeric_limits<size_t>::max())
1753e519524SHoward Hinnant return false;
1763e519524SHoward Hinnant ++__count_;
1773e519524SHoward Hinnant __id_ = id;
1783e519524SHoward Hinnant return true;
1793e519524SHoward Hinnant }
1803e519524SHoward Hinnant return false;
1813e519524SHoward Hinnant }
1823e519524SHoward Hinnant
1833e519524SHoward Hinnant void
unlock()1845601305fSLouis Dionne recursive_timed_mutex::unlock() noexcept
1853e519524SHoward Hinnant {
1863e519524SHoward Hinnant unique_lock<mutex> lk(__m_);
1873e519524SHoward Hinnant if (--__count_ == 0)
1883e519524SHoward Hinnant {
1892e80d01fSMarshall Clow __id_.__reset();
1903e519524SHoward Hinnant lk.unlock();
1913e519524SHoward Hinnant __cv_.notify_one();
1923e519524SHoward Hinnant }
1933e519524SHoward Hinnant }
1943e519524SHoward Hinnant
195b3fcc67fSJonathan Roelofs #endif // !_LIBCPP_HAS_NO_THREADS
196b3fcc67fSJonathan Roelofs
1973e519524SHoward Hinnant // If dispatch_once_f ever handles C++ exceptions, and if one can get to it
1983e519524SHoward Hinnant // without illegal macros (unexpected macros not beginning with _UpperCase or
1993e519524SHoward Hinnant // __lowercase), and if it stops spinning waiting threads, then call_once should
2003e519524SHoward Hinnant // call into dispatch_once_f instead of here. Relevant radar this code needs to
2013e519524SHoward Hinnant // keep in sync with: 7741191.
2023e519524SHoward Hinnant
203b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
20405337a75SArthur O'Dwyer static constinit __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER;
20505337a75SArthur O'Dwyer static constinit __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER;
206b3fcc67fSJonathan Roelofs #endif
2073e519524SHoward Hinnant
__call_once(volatile once_flag::_State_type & flag,void * arg,void (* func)(void *))2080fd00a58SNico Weber void __call_once(volatile once_flag::_State_type& flag, void* arg,
2090fd00a58SNico Weber void (*func)(void*))
2103e519524SHoward Hinnant {
211b3fcc67fSJonathan Roelofs #if defined(_LIBCPP_HAS_NO_THREADS)
212b3fcc67fSJonathan Roelofs if (flag == 0)
213b3fcc67fSJonathan Roelofs {
214b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_NO_EXCEPTIONS
215b3fcc67fSJonathan Roelofs try
216b3fcc67fSJonathan Roelofs {
217b3fcc67fSJonathan Roelofs #endif // _LIBCPP_NO_EXCEPTIONS
218b3fcc67fSJonathan Roelofs flag = 1;
219b3fcc67fSJonathan Roelofs func(arg);
2200fd00a58SNico Weber flag = ~once_flag::_State_type(0);
221b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_NO_EXCEPTIONS
222b3fcc67fSJonathan Roelofs }
223b3fcc67fSJonathan Roelofs catch (...)
224b3fcc67fSJonathan Roelofs {
2250fd00a58SNico Weber flag = 0;
226b3fcc67fSJonathan Roelofs throw;
227b3fcc67fSJonathan Roelofs }
228b3fcc67fSJonathan Roelofs #endif // _LIBCPP_NO_EXCEPTIONS
229b3fcc67fSJonathan Roelofs }
230b3fcc67fSJonathan Roelofs #else // !_LIBCPP_HAS_NO_THREADS
231c7e4239fSAsiri Rathnayake __libcpp_mutex_lock(&mut);
2323e519524SHoward Hinnant while (flag == 1)
233c7e4239fSAsiri Rathnayake __libcpp_condvar_wait(&cv, &mut);
2343e519524SHoward Hinnant if (flag == 0)
2353e519524SHoward Hinnant {
23654b409fdSHoward Hinnant #ifndef _LIBCPP_NO_EXCEPTIONS
2373e519524SHoward Hinnant try
2383e519524SHoward Hinnant {
239940e211cSHoward Hinnant #endif // _LIBCPP_NO_EXCEPTIONS
2400fd00a58SNico Weber __libcpp_relaxed_store(&flag, once_flag::_State_type(1));
241c7e4239fSAsiri Rathnayake __libcpp_mutex_unlock(&mut);
2423e519524SHoward Hinnant func(arg);
243c7e4239fSAsiri Rathnayake __libcpp_mutex_lock(&mut);
2440fd00a58SNico Weber __libcpp_atomic_store(&flag, ~once_flag::_State_type(0),
2450fd00a58SNico Weber _AO_Release);
246c7e4239fSAsiri Rathnayake __libcpp_mutex_unlock(&mut);
247c7e4239fSAsiri Rathnayake __libcpp_condvar_broadcast(&cv);
24854b409fdSHoward Hinnant #ifndef _LIBCPP_NO_EXCEPTIONS
2493e519524SHoward Hinnant }
2503e519524SHoward Hinnant catch (...)
2513e519524SHoward Hinnant {
252c7e4239fSAsiri Rathnayake __libcpp_mutex_lock(&mut);
2530fd00a58SNico Weber __libcpp_relaxed_store(&flag, once_flag::_State_type(0));
254c7e4239fSAsiri Rathnayake __libcpp_mutex_unlock(&mut);
255c7e4239fSAsiri Rathnayake __libcpp_condvar_broadcast(&cv);
2563e519524SHoward Hinnant throw;
2573e519524SHoward Hinnant }
258940e211cSHoward Hinnant #endif // _LIBCPP_NO_EXCEPTIONS
2593e519524SHoward Hinnant }
2603e519524SHoward Hinnant else
261c7e4239fSAsiri Rathnayake __libcpp_mutex_unlock(&mut);
262b3fcc67fSJonathan Roelofs #endif // !_LIBCPP_HAS_NO_THREADS
2633e519524SHoward Hinnant }
2643e519524SHoward Hinnant
2653e519524SHoward Hinnant _LIBCPP_END_NAMESPACE_STD
266bbb0f2c7SArthur O'Dwyer
267bbb0f2c7SArthur O'Dwyer _LIBCPP_POP_MACROS
268