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