1349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 981ad6265SDimitry Andric #include <__assert> 1081ad6265SDimitry Andric #include <limits> 1181ad6265SDimitry Andric #include <mutex> 1281ad6265SDimitry Andric #include <system_error> 1381ad6265SDimitry Andric 140b57cec5SDimitry Andric #include "include/atomic_support.h" 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS 17480093f4SDimitry Andric # if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB) 180b57cec5SDimitry Andric # pragma comment(lib, "pthread") 190b57cec5SDimitry Andric # endif 200b57cec5SDimitry Andric #endif 210b57cec5SDimitry Andric 2281ad6265SDimitry Andric _LIBCPP_PUSH_MACROS 2381ad6265SDimitry Andric #include <__undef_macros> 2481ad6265SDimitry Andric 250b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 2681ad6265SDimitry Andric 270b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS 280b57cec5SDimitry Andric 29e40139ffSDimitry Andric const defer_lock_t defer_lock{}; 30e40139ffSDimitry Andric const try_to_lock_t try_to_lock{}; 31e40139ffSDimitry Andric const adopt_lock_t adopt_lock{}; 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric // ~mutex is defined elsewhere 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric void 360b57cec5SDimitry Andric mutex::lock() 370b57cec5SDimitry Andric { 380b57cec5SDimitry Andric int ec = __libcpp_mutex_lock(&__m_); 390b57cec5SDimitry Andric if (ec) 400b57cec5SDimitry Andric __throw_system_error(ec, "mutex lock failed"); 410b57cec5SDimitry Andric } 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric bool 44fe6060f1SDimitry Andric mutex::try_lock() noexcept 450b57cec5SDimitry Andric { 460b57cec5SDimitry Andric return __libcpp_mutex_trylock(&__m_); 470b57cec5SDimitry Andric } 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric void 50fe6060f1SDimitry Andric mutex::unlock() noexcept 510b57cec5SDimitry Andric { 520b57cec5SDimitry Andric int ec = __libcpp_mutex_unlock(&__m_); 530b57cec5SDimitry Andric (void)ec; 540b57cec5SDimitry Andric _LIBCPP_ASSERT(ec == 0, "call to mutex::unlock failed"); 550b57cec5SDimitry Andric } 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric // recursive_mutex 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric recursive_mutex::recursive_mutex() 600b57cec5SDimitry Andric { 610b57cec5SDimitry Andric int ec = __libcpp_recursive_mutex_init(&__m_); 620b57cec5SDimitry Andric if (ec) 630b57cec5SDimitry Andric __throw_system_error(ec, "recursive_mutex constructor failed"); 640b57cec5SDimitry Andric } 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric recursive_mutex::~recursive_mutex() 670b57cec5SDimitry Andric { 680b57cec5SDimitry Andric int e = __libcpp_recursive_mutex_destroy(&__m_); 690b57cec5SDimitry Andric (void)e; 700b57cec5SDimitry Andric _LIBCPP_ASSERT(e == 0, "call to ~recursive_mutex() failed"); 710b57cec5SDimitry Andric } 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric void 740b57cec5SDimitry Andric recursive_mutex::lock() 750b57cec5SDimitry Andric { 760b57cec5SDimitry Andric int ec = __libcpp_recursive_mutex_lock(&__m_); 770b57cec5SDimitry Andric if (ec) 780b57cec5SDimitry Andric __throw_system_error(ec, "recursive_mutex lock failed"); 790b57cec5SDimitry Andric } 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric void 82fe6060f1SDimitry Andric recursive_mutex::unlock() noexcept 830b57cec5SDimitry Andric { 840b57cec5SDimitry Andric int e = __libcpp_recursive_mutex_unlock(&__m_); 850b57cec5SDimitry Andric (void)e; 860b57cec5SDimitry Andric _LIBCPP_ASSERT(e == 0, "call to recursive_mutex::unlock() failed"); 870b57cec5SDimitry Andric } 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric bool 90fe6060f1SDimitry Andric recursive_mutex::try_lock() noexcept 910b57cec5SDimitry Andric { 920b57cec5SDimitry Andric return __libcpp_recursive_mutex_trylock(&__m_); 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric // timed_mutex 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric timed_mutex::timed_mutex() 980b57cec5SDimitry Andric : __locked_(false) 990b57cec5SDimitry Andric { 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric timed_mutex::~timed_mutex() 1030b57cec5SDimitry Andric { 1040b57cec5SDimitry Andric lock_guard<mutex> _(__m_); 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric void 1080b57cec5SDimitry Andric timed_mutex::lock() 1090b57cec5SDimitry Andric { 1100b57cec5SDimitry Andric unique_lock<mutex> lk(__m_); 1110b57cec5SDimitry Andric while (__locked_) 1120b57cec5SDimitry Andric __cv_.wait(lk); 1130b57cec5SDimitry Andric __locked_ = true; 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric bool 117fe6060f1SDimitry Andric timed_mutex::try_lock() noexcept 1180b57cec5SDimitry Andric { 1190b57cec5SDimitry Andric unique_lock<mutex> lk(__m_, try_to_lock); 1200b57cec5SDimitry Andric if (lk.owns_lock() && !__locked_) 1210b57cec5SDimitry Andric { 1220b57cec5SDimitry Andric __locked_ = true; 1230b57cec5SDimitry Andric return true; 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric return false; 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric void 129fe6060f1SDimitry Andric timed_mutex::unlock() noexcept 1300b57cec5SDimitry Andric { 1310b57cec5SDimitry Andric lock_guard<mutex> _(__m_); 1320b57cec5SDimitry Andric __locked_ = false; 1330b57cec5SDimitry Andric __cv_.notify_one(); 1340b57cec5SDimitry Andric } 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric // recursive_timed_mutex 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric recursive_timed_mutex::recursive_timed_mutex() 1390b57cec5SDimitry Andric : __count_(0), 1400b57cec5SDimitry Andric __id_{} 1410b57cec5SDimitry Andric { 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric recursive_timed_mutex::~recursive_timed_mutex() 1450b57cec5SDimitry Andric { 1460b57cec5SDimitry Andric lock_guard<mutex> _(__m_); 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric void 1500b57cec5SDimitry Andric recursive_timed_mutex::lock() 1510b57cec5SDimitry Andric { 1520b57cec5SDimitry Andric __thread_id id = this_thread::get_id(); 1530b57cec5SDimitry Andric unique_lock<mutex> lk(__m_); 1540b57cec5SDimitry Andric if (id ==__id_) 1550b57cec5SDimitry Andric { 1560b57cec5SDimitry Andric if (__count_ == numeric_limits<size_t>::max()) 1570b57cec5SDimitry Andric __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached"); 1580b57cec5SDimitry Andric ++__count_; 1590b57cec5SDimitry Andric return; 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric while (__count_ != 0) 1620b57cec5SDimitry Andric __cv_.wait(lk); 1630b57cec5SDimitry Andric __count_ = 1; 1640b57cec5SDimitry Andric __id_ = id; 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric bool 168fe6060f1SDimitry Andric recursive_timed_mutex::try_lock() noexcept 1690b57cec5SDimitry Andric { 1700b57cec5SDimitry Andric __thread_id id = this_thread::get_id(); 1710b57cec5SDimitry Andric unique_lock<mutex> lk(__m_, try_to_lock); 1720b57cec5SDimitry Andric if (lk.owns_lock() && (__count_ == 0 || id == __id_)) 1730b57cec5SDimitry Andric { 1740b57cec5SDimitry Andric if (__count_ == numeric_limits<size_t>::max()) 1750b57cec5SDimitry Andric return false; 1760b57cec5SDimitry Andric ++__count_; 1770b57cec5SDimitry Andric __id_ = id; 1780b57cec5SDimitry Andric return true; 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric return false; 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric void 184fe6060f1SDimitry Andric recursive_timed_mutex::unlock() noexcept 1850b57cec5SDimitry Andric { 1860b57cec5SDimitry Andric unique_lock<mutex> lk(__m_); 1870b57cec5SDimitry Andric if (--__count_ == 0) 1880b57cec5SDimitry Andric { 1890b57cec5SDimitry Andric __id_.__reset(); 1900b57cec5SDimitry Andric lk.unlock(); 1910b57cec5SDimitry Andric __cv_.notify_one(); 1920b57cec5SDimitry Andric } 1930b57cec5SDimitry Andric } 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric #endif // !_LIBCPP_HAS_NO_THREADS 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric // If dispatch_once_f ever handles C++ exceptions, and if one can get to it 1980b57cec5SDimitry Andric // without illegal macros (unexpected macros not beginning with _UpperCase or 1990b57cec5SDimitry Andric // __lowercase), and if it stops spinning waiting threads, then call_once should 2000b57cec5SDimitry Andric // call into dispatch_once_f instead of here. Relevant radar this code needs to 2010b57cec5SDimitry Andric // keep in sync with: 7741191. 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS 20481ad6265SDimitry Andric static constinit __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER; 20581ad6265SDimitry Andric static constinit __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER; 2060b57cec5SDimitry Andric #endif 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric void __call_once(volatile once_flag::_State_type& flag, void* arg, 2090b57cec5SDimitry Andric void (*func)(void*)) 2100b57cec5SDimitry Andric { 2110b57cec5SDimitry Andric #if defined(_LIBCPP_HAS_NO_THREADS) 2120b57cec5SDimitry Andric if (flag == 0) 2130b57cec5SDimitry Andric { 2140b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS 2150b57cec5SDimitry Andric try 2160b57cec5SDimitry Andric { 2170b57cec5SDimitry Andric #endif // _LIBCPP_NO_EXCEPTIONS 2180b57cec5SDimitry Andric flag = 1; 2190b57cec5SDimitry Andric func(arg); 2200b57cec5SDimitry Andric flag = ~once_flag::_State_type(0); 2210b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric catch (...) 2240b57cec5SDimitry Andric { 2250b57cec5SDimitry Andric flag = 0; 2260b57cec5SDimitry Andric throw; 2270b57cec5SDimitry Andric } 2280b57cec5SDimitry Andric #endif // _LIBCPP_NO_EXCEPTIONS 2290b57cec5SDimitry Andric } 2300b57cec5SDimitry Andric #else // !_LIBCPP_HAS_NO_THREADS 2310b57cec5SDimitry Andric __libcpp_mutex_lock(&mut); 2320b57cec5SDimitry Andric while (flag == 1) 2330b57cec5SDimitry Andric __libcpp_condvar_wait(&cv, &mut); 2340b57cec5SDimitry Andric if (flag == 0) 2350b57cec5SDimitry Andric { 2360b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS 2370b57cec5SDimitry Andric try 2380b57cec5SDimitry Andric { 2390b57cec5SDimitry Andric #endif // _LIBCPP_NO_EXCEPTIONS 2400b57cec5SDimitry Andric __libcpp_relaxed_store(&flag, once_flag::_State_type(1)); 2410b57cec5SDimitry Andric __libcpp_mutex_unlock(&mut); 2420b57cec5SDimitry Andric func(arg); 2430b57cec5SDimitry Andric __libcpp_mutex_lock(&mut); 2440b57cec5SDimitry Andric __libcpp_atomic_store(&flag, ~once_flag::_State_type(0), 2450b57cec5SDimitry Andric _AO_Release); 2460b57cec5SDimitry Andric __libcpp_mutex_unlock(&mut); 2470b57cec5SDimitry Andric __libcpp_condvar_broadcast(&cv); 2480b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS 2490b57cec5SDimitry Andric } 2500b57cec5SDimitry Andric catch (...) 2510b57cec5SDimitry Andric { 2520b57cec5SDimitry Andric __libcpp_mutex_lock(&mut); 2530b57cec5SDimitry Andric __libcpp_relaxed_store(&flag, once_flag::_State_type(0)); 2540b57cec5SDimitry Andric __libcpp_mutex_unlock(&mut); 2550b57cec5SDimitry Andric __libcpp_condvar_broadcast(&cv); 2560b57cec5SDimitry Andric throw; 2570b57cec5SDimitry Andric } 2580b57cec5SDimitry Andric #endif // _LIBCPP_NO_EXCEPTIONS 2590b57cec5SDimitry Andric } 2600b57cec5SDimitry Andric else 2610b57cec5SDimitry Andric __libcpp_mutex_unlock(&mut); 2620b57cec5SDimitry Andric #endif // !_LIBCPP_HAS_NO_THREADS 2630b57cec5SDimitry Andric } 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD 26681ad6265SDimitry Andric 26781ad6265SDimitry Andric _LIBCPP_POP_MACROS 268