xref: /freebsd-12.1/contrib/libc++/src/mutex.cpp (revision 4173b67f)
17a984708SDavid Chisnall //===------------------------- mutex.cpp ----------------------------------===//
27a984708SDavid Chisnall //
37a984708SDavid Chisnall //                     The LLVM Compiler Infrastructure
47a984708SDavid Chisnall //
57a984708SDavid Chisnall // This file is dual licensed under the MIT and the University of Illinois Open
67a984708SDavid Chisnall // Source Licenses. See LICENSE.TXT for details.
77a984708SDavid Chisnall //
87a984708SDavid Chisnall //===----------------------------------------------------------------------===//
97a984708SDavid Chisnall 
107a984708SDavid Chisnall #include "mutex"
117a984708SDavid Chisnall #include "limits"
127a984708SDavid Chisnall #include "system_error"
139729cf09SDimitry Andric #include "include/atomic_support.h"
14f9448bf3SDimitry Andric #include "__undef_macros"
157a984708SDavid Chisnall 
167a984708SDavid Chisnall _LIBCPP_BEGIN_NAMESPACE_STD
17d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
187a984708SDavid Chisnall 
197a984708SDavid Chisnall const defer_lock_t  defer_lock = {};
207a984708SDavid Chisnall const try_to_lock_t try_to_lock = {};
217a984708SDavid Chisnall const adopt_lock_t  adopt_lock = {};
227a984708SDavid Chisnall 
~mutex()237a984708SDavid Chisnall mutex::~mutex()
247a984708SDavid Chisnall {
257c82a1ecSDimitry Andric     __libcpp_mutex_destroy(&__m_);
267a984708SDavid Chisnall }
277a984708SDavid Chisnall 
287a984708SDavid Chisnall void
lock()297a984708SDavid Chisnall mutex::lock()
307a984708SDavid Chisnall {
317c82a1ecSDimitry Andric     int ec = __libcpp_mutex_lock(&__m_);
327a984708SDavid Chisnall     if (ec)
337a984708SDavid Chisnall         __throw_system_error(ec, "mutex lock failed");
347a984708SDavid Chisnall }
357a984708SDavid Chisnall 
367a984708SDavid Chisnall bool
try_lock()37936e9439SDimitry Andric mutex::try_lock() _NOEXCEPT
387a984708SDavid Chisnall {
39540d2a8bSDimitry Andric     return __libcpp_mutex_trylock(&__m_);
407a984708SDavid Chisnall }
417a984708SDavid Chisnall 
427a984708SDavid Chisnall void
unlock()43936e9439SDimitry Andric mutex::unlock() _NOEXCEPT
447a984708SDavid Chisnall {
457c82a1ecSDimitry Andric     int ec = __libcpp_mutex_unlock(&__m_);
464f7ab58eSDimitry Andric     (void)ec;
47540d2a8bSDimitry Andric     _LIBCPP_ASSERT(ec == 0, "call to mutex::unlock failed");
487a984708SDavid Chisnall }
497a984708SDavid Chisnall 
507a984708SDavid Chisnall // recursive_mutex
517a984708SDavid Chisnall 
recursive_mutex()527a984708SDavid Chisnall recursive_mutex::recursive_mutex()
537a984708SDavid Chisnall {
547c82a1ecSDimitry Andric     int ec = __libcpp_recursive_mutex_init(&__m_);
557a984708SDavid Chisnall     if (ec)
567a984708SDavid Chisnall         __throw_system_error(ec, "recursive_mutex constructor failed");
577a984708SDavid Chisnall }
587a984708SDavid Chisnall 
~recursive_mutex()597a984708SDavid Chisnall recursive_mutex::~recursive_mutex()
607a984708SDavid Chisnall {
61aed8d94eSDimitry Andric     int e = __libcpp_recursive_mutex_destroy(&__m_);
624f7ab58eSDimitry Andric     (void)e;
63540d2a8bSDimitry Andric     _LIBCPP_ASSERT(e == 0, "call to ~recursive_mutex() failed");
647a984708SDavid Chisnall }
657a984708SDavid Chisnall 
667a984708SDavid Chisnall void
lock()677a984708SDavid Chisnall recursive_mutex::lock()
687a984708SDavid Chisnall {
69aed8d94eSDimitry Andric     int ec = __libcpp_recursive_mutex_lock(&__m_);
707a984708SDavid Chisnall     if (ec)
717a984708SDavid Chisnall         __throw_system_error(ec, "recursive_mutex lock failed");
727a984708SDavid Chisnall }
737a984708SDavid Chisnall 
747a984708SDavid Chisnall void
unlock()75936e9439SDimitry Andric recursive_mutex::unlock() _NOEXCEPT
767a984708SDavid Chisnall {
77aed8d94eSDimitry Andric     int e = __libcpp_recursive_mutex_unlock(&__m_);
784f7ab58eSDimitry Andric     (void)e;
79540d2a8bSDimitry Andric     _LIBCPP_ASSERT(e == 0, "call to recursive_mutex::unlock() failed");
807a984708SDavid Chisnall }
817a984708SDavid Chisnall 
827a984708SDavid Chisnall bool
try_lock()83936e9439SDimitry Andric recursive_mutex::try_lock() _NOEXCEPT
847a984708SDavid Chisnall {
85540d2a8bSDimitry Andric     return __libcpp_recursive_mutex_trylock(&__m_);
867a984708SDavid Chisnall }
877a984708SDavid Chisnall 
887a984708SDavid Chisnall // timed_mutex
897a984708SDavid Chisnall 
timed_mutex()907a984708SDavid Chisnall timed_mutex::timed_mutex()
917a984708SDavid Chisnall     : __locked_(false)
927a984708SDavid Chisnall {
937a984708SDavid Chisnall }
947a984708SDavid Chisnall 
~timed_mutex()957a984708SDavid Chisnall timed_mutex::~timed_mutex()
967a984708SDavid Chisnall {
977a984708SDavid Chisnall     lock_guard<mutex> _(__m_);
987a984708SDavid Chisnall }
997a984708SDavid Chisnall 
1007a984708SDavid Chisnall void
lock()1017a984708SDavid Chisnall timed_mutex::lock()
1027a984708SDavid Chisnall {
1037a984708SDavid Chisnall     unique_lock<mutex> lk(__m_);
1047a984708SDavid Chisnall     while (__locked_)
1057a984708SDavid Chisnall         __cv_.wait(lk);
1067a984708SDavid Chisnall     __locked_ = true;
1077a984708SDavid Chisnall }
1087a984708SDavid Chisnall 
1097a984708SDavid Chisnall bool
try_lock()110936e9439SDimitry Andric timed_mutex::try_lock() _NOEXCEPT
1117a984708SDavid Chisnall {
1127a984708SDavid Chisnall     unique_lock<mutex> lk(__m_, try_to_lock);
1137a984708SDavid Chisnall     if (lk.owns_lock() && !__locked_)
1147a984708SDavid Chisnall     {
1157a984708SDavid Chisnall         __locked_ = true;
1167a984708SDavid Chisnall         return true;
1177a984708SDavid Chisnall     }
1187a984708SDavid Chisnall     return false;
1197a984708SDavid Chisnall }
1207a984708SDavid Chisnall 
1217a984708SDavid Chisnall void
unlock()122936e9439SDimitry Andric timed_mutex::unlock() _NOEXCEPT
1237a984708SDavid Chisnall {
1247a984708SDavid Chisnall     lock_guard<mutex> _(__m_);
1257a984708SDavid Chisnall     __locked_ = false;
1267a984708SDavid Chisnall     __cv_.notify_one();
1277a984708SDavid Chisnall }
1287a984708SDavid Chisnall 
1297a984708SDavid Chisnall // recursive_timed_mutex
1307a984708SDavid Chisnall 
recursive_timed_mutex()1317a984708SDavid Chisnall recursive_timed_mutex::recursive_timed_mutex()
1327a984708SDavid Chisnall     : __count_(0),
133*4173b67fSDimitry Andric       __id_{}
1347a984708SDavid Chisnall {
1357a984708SDavid Chisnall }
1367a984708SDavid Chisnall 
~recursive_timed_mutex()1377a984708SDavid Chisnall recursive_timed_mutex::~recursive_timed_mutex()
1387a984708SDavid Chisnall {
1397a984708SDavid Chisnall     lock_guard<mutex> _(__m_);
1407a984708SDavid Chisnall }
1417a984708SDavid Chisnall 
1427a984708SDavid Chisnall void
lock()1437a984708SDavid Chisnall recursive_timed_mutex::lock()
1447a984708SDavid Chisnall {
145*4173b67fSDimitry Andric     __thread_id id = this_thread::get_id();
1467a984708SDavid Chisnall     unique_lock<mutex> lk(__m_);
147*4173b67fSDimitry Andric     if (id ==__id_)
1487a984708SDavid Chisnall     {
1497a984708SDavid Chisnall         if (__count_ == numeric_limits<size_t>::max())
1507a984708SDavid Chisnall             __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached");
1517a984708SDavid Chisnall         ++__count_;
1527a984708SDavid Chisnall         return;
1537a984708SDavid Chisnall     }
1547a984708SDavid Chisnall     while (__count_ != 0)
1557a984708SDavid Chisnall         __cv_.wait(lk);
1567a984708SDavid Chisnall     __count_ = 1;
1577a984708SDavid Chisnall     __id_ = id;
1587a984708SDavid Chisnall }
1597a984708SDavid Chisnall 
1607a984708SDavid Chisnall bool
try_lock()161936e9439SDimitry Andric recursive_timed_mutex::try_lock() _NOEXCEPT
1627a984708SDavid Chisnall {
163*4173b67fSDimitry Andric     __thread_id id = this_thread::get_id();
1647a984708SDavid Chisnall     unique_lock<mutex> lk(__m_, try_to_lock);
165*4173b67fSDimitry Andric     if (lk.owns_lock() && (__count_ == 0 || id == __id_))
1667a984708SDavid Chisnall     {
1677a984708SDavid Chisnall         if (__count_ == numeric_limits<size_t>::max())
1687a984708SDavid Chisnall             return false;
1697a984708SDavid Chisnall         ++__count_;
1707a984708SDavid Chisnall         __id_ = id;
1717a984708SDavid Chisnall         return true;
1727a984708SDavid Chisnall     }
1737a984708SDavid Chisnall     return false;
1747a984708SDavid Chisnall }
1757a984708SDavid Chisnall 
1767a984708SDavid Chisnall void
unlock()177936e9439SDimitry Andric recursive_timed_mutex::unlock() _NOEXCEPT
1787a984708SDavid Chisnall {
1797a984708SDavid Chisnall     unique_lock<mutex> lk(__m_);
1807a984708SDavid Chisnall     if (--__count_ == 0)
1817a984708SDavid Chisnall     {
182*4173b67fSDimitry Andric         __id_.__reset();
1837a984708SDavid Chisnall         lk.unlock();
1847a984708SDavid Chisnall         __cv_.notify_one();
1857a984708SDavid Chisnall     }
1867a984708SDavid Chisnall }
1877a984708SDavid Chisnall 
188d72607e9SDimitry Andric #endif // !_LIBCPP_HAS_NO_THREADS
189d72607e9SDimitry Andric 
1907a984708SDavid Chisnall // If dispatch_once_f ever handles C++ exceptions, and if one can get to it
1917a984708SDavid Chisnall // without illegal macros (unexpected macros not beginning with _UpperCase or
1927a984708SDavid Chisnall // __lowercase), and if it stops spinning waiting threads, then call_once should
1937a984708SDavid Chisnall // call into dispatch_once_f instead of here. Relevant radar this code needs to
1947a984708SDavid Chisnall // keep in sync with:  7741191.
1957a984708SDavid Chisnall 
196d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
197aed8d94eSDimitry Andric _LIBCPP_SAFE_STATIC static __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER;
198aed8d94eSDimitry Andric _LIBCPP_SAFE_STATIC static __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER;
199d72607e9SDimitry Andric #endif
2007a984708SDavid Chisnall 
2017a984708SDavid Chisnall void
__call_once(volatile unsigned long & flag,void * arg,void (* func)(void *))2027a984708SDavid Chisnall __call_once(volatile unsigned long& flag, void* arg, void(*func)(void*))
2037a984708SDavid Chisnall {
204d72607e9SDimitry Andric #if defined(_LIBCPP_HAS_NO_THREADS)
205d72607e9SDimitry Andric     if (flag == 0)
206d72607e9SDimitry Andric     {
207d72607e9SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
208d72607e9SDimitry Andric         try
209d72607e9SDimitry Andric         {
210d72607e9SDimitry Andric #endif  // _LIBCPP_NO_EXCEPTIONS
211d72607e9SDimitry Andric             flag = 1;
212d72607e9SDimitry Andric             func(arg);
213d72607e9SDimitry Andric             flag = ~0ul;
214d72607e9SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
215d72607e9SDimitry Andric         }
216d72607e9SDimitry Andric         catch (...)
217d72607e9SDimitry Andric         {
218d72607e9SDimitry Andric             flag = 0ul;
219d72607e9SDimitry Andric             throw;
220d72607e9SDimitry Andric         }
221d72607e9SDimitry Andric #endif  // _LIBCPP_NO_EXCEPTIONS
222d72607e9SDimitry Andric     }
223d72607e9SDimitry Andric #else // !_LIBCPP_HAS_NO_THREADS
2247c82a1ecSDimitry Andric     __libcpp_mutex_lock(&mut);
2257a984708SDavid Chisnall     while (flag == 1)
2267c82a1ecSDimitry Andric         __libcpp_condvar_wait(&cv, &mut);
2277a984708SDavid Chisnall     if (flag == 0)
2287a984708SDavid Chisnall     {
2297a984708SDavid Chisnall #ifndef _LIBCPP_NO_EXCEPTIONS
2307a984708SDavid Chisnall         try
2317a984708SDavid Chisnall         {
2327a984708SDavid Chisnall #endif  // _LIBCPP_NO_EXCEPTIONS
233854fa44bSDimitry Andric             __libcpp_relaxed_store(&flag, 1ul);
2347c82a1ecSDimitry Andric             __libcpp_mutex_unlock(&mut);
2357a984708SDavid Chisnall             func(arg);
2367c82a1ecSDimitry Andric             __libcpp_mutex_lock(&mut);
237aed8d94eSDimitry Andric             __libcpp_atomic_store(&flag, ~0ul, _AO_Release);
2387c82a1ecSDimitry Andric             __libcpp_mutex_unlock(&mut);
2397c82a1ecSDimitry Andric             __libcpp_condvar_broadcast(&cv);
2407a984708SDavid Chisnall #ifndef _LIBCPP_NO_EXCEPTIONS
2417a984708SDavid Chisnall         }
2427a984708SDavid Chisnall         catch (...)
2437a984708SDavid Chisnall         {
2447c82a1ecSDimitry Andric             __libcpp_mutex_lock(&mut);
245854fa44bSDimitry Andric             __libcpp_relaxed_store(&flag, 0ul);
2467c82a1ecSDimitry Andric             __libcpp_mutex_unlock(&mut);
2477c82a1ecSDimitry Andric             __libcpp_condvar_broadcast(&cv);
2487a984708SDavid Chisnall             throw;
2497a984708SDavid Chisnall         }
2507a984708SDavid Chisnall #endif  // _LIBCPP_NO_EXCEPTIONS
2517a984708SDavid Chisnall     }
2527a984708SDavid Chisnall     else
2537c82a1ecSDimitry Andric         __libcpp_mutex_unlock(&mut);
254d72607e9SDimitry Andric #endif // !_LIBCPP_HAS_NO_THREADS
255d72607e9SDimitry Andric 
2567a984708SDavid Chisnall }
2577a984708SDavid Chisnall 
2587a984708SDavid Chisnall _LIBCPP_END_NAMESPACE_STD
259