13e519524SHoward Hinnant// -*- C++ -*-
23e519524SHoward Hinnant//===----------------------------------------------------------------------===//
33e519524SHoward Hinnant//
457b08b09SChandler Carruth// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
557b08b09SChandler Carruth// See https://llvm.org/LICENSE.txt for license information.
657b08b09SChandler Carruth// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
73e519524SHoward Hinnant//
83e519524SHoward Hinnant//===----------------------------------------------------------------------===//
93e519524SHoward Hinnant
103e519524SHoward Hinnant#ifndef _LIBCPP___MUTEX_BASE
113e519524SHoward Hinnant#define _LIBCPP___MUTEX_BASE
123e519524SHoward Hinnant
13489637e6SNikolas Klauser#include <__chrono/duration.h>
14489637e6SNikolas Klauser#include <__chrono/steady_clock.h>
15489637e6SNikolas Klauser#include <__chrono/system_clock.h>
16489637e6SNikolas Klauser#include <__chrono/time_point.h>
173e519524SHoward Hinnant#include <__config>
18bfbd73f8SArthur O'Dwyer#include <__threading_support>
195726e559SLouis Dionne#include <ratio>
203e519524SHoward Hinnant#include <system_error>
2185e26f56SDan Albert#include <time.h>
223e519524SHoward Hinnant
23073458b1SHoward Hinnant#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
243e519524SHoward Hinnant#  pragma GCC system_header
25073458b1SHoward Hinnant#endif
263e519524SHoward Hinnant
27a016efb1SEric Fiselier_LIBCPP_PUSH_MACROS
28a016efb1SEric Fiselier#include <__undef_macros>
29a016efb1SEric Fiselier
30a016efb1SEric Fiselier
313e519524SHoward Hinnant_LIBCPP_BEGIN_NAMESPACE_STD
323e519524SHoward Hinnant
33b3fcc67fSJonathan Roelofs#ifndef _LIBCPP_HAS_NO_THREADS
34b3fcc67fSJonathan Roelofs
357865b2e9SEric Fiselierclass _LIBCPP_TYPE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mutex
363e519524SHoward Hinnant{
37816739caSMarshall Clow    __libcpp_mutex_t __m_ = _LIBCPP_MUTEX_INITIALIZER;
383e519524SHoward Hinnant
393e519524SHoward Hinnantpublic:
40f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY
418baf8383SEric Fiselier    _LIBCPP_CONSTEXPR mutex() = default;
428baf8383SEric Fiselier
438baf8383SEric Fiselier    mutex(const mutex&) = delete;
448baf8383SEric Fiselier    mutex& operator=(const mutex&) = delete;
458baf8383SEric Fiselier
468baf8383SEric Fiselier#if defined(_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION)
478baf8383SEric Fiselier    ~mutex() = default;
48bfa7990bSHoward Hinnant#else
4965d4d5e9SRichard Smith    ~mutex() _NOEXCEPT;
508baf8383SEric Fiselier#endif
513e519524SHoward Hinnant
527865b2e9SEric Fiselier    void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability());
537865b2e9SEric Fiselier    bool try_lock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
547865b2e9SEric Fiselier    void unlock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
553e519524SHoward Hinnant
56c7e4239fSAsiri Rathnayake    typedef __libcpp_mutex_t* native_handle_type;
57f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
583e519524SHoward Hinnant};
593e519524SHoward Hinnant
608551d0e3SEric Fiselierstatic_assert(is_nothrow_default_constructible<mutex>::value,
618551d0e3SEric Fiselier              "the default constructor for std::mutex must be nothrow");
628551d0e3SEric Fiselier
63e16f2cb6SLouis Dionnestruct _LIBCPP_TYPE_VIS defer_lock_t { explicit defer_lock_t() = default; };
64e16f2cb6SLouis Dionnestruct _LIBCPP_TYPE_VIS try_to_lock_t { explicit try_to_lock_t() = default; };
65e16f2cb6SLouis Dionnestruct _LIBCPP_TYPE_VIS adopt_lock_t { explicit adopt_lock_t() = default; };
663e519524SHoward Hinnant
67c8e84ff2SLouis Dionne#if defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY)
683e519524SHoward Hinnant
699b3222f6SLouis Dionneextern _LIBCPP_EXPORTED_FROM_ABI const defer_lock_t  defer_lock;
709b3222f6SLouis Dionneextern _LIBCPP_EXPORTED_FROM_ABI const try_to_lock_t try_to_lock;
719b3222f6SLouis Dionneextern _LIBCPP_EXPORTED_FROM_ABI const adopt_lock_t  adopt_lock;
723e519524SHoward Hinnant
7302e610efSHoward Hinnant#else
7402e610efSHoward Hinnant
75cb793e1aSLouis Dionne/* inline */ constexpr defer_lock_t  defer_lock  = defer_lock_t();
76cb793e1aSLouis Dionne/* inline */ constexpr try_to_lock_t try_to_lock = try_to_lock_t();
77cb793e1aSLouis Dionne/* inline */ constexpr adopt_lock_t  adopt_lock  = adopt_lock_t();
7802e610efSHoward Hinnant
7902e610efSHoward Hinnant#endif
803e519524SHoward Hinnant
813e519524SHoward Hinnanttemplate <class _Mutex>
82e2f2d1edSEric Fiselierclass _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable)
8348f35e07SEric Fiselierlock_guard
843e519524SHoward Hinnant{
853e519524SHoward Hinnantpublic:
863e519524SHoward Hinnant    typedef _Mutex mutex_type;
873e519524SHoward Hinnant
883e519524SHoward Hinnantprivate:
893e519524SHoward Hinnant    mutex_type& __m_;
903e519524SHoward Hinnantpublic:
913e519524SHoward Hinnant
9286dd28a5SLouis Dionne    _LIBCPP_NODISCARD_EXT _LIBCPP_INLINE_VISIBILITY
937865b2e9SEric Fiselier    explicit lock_guard(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m))
943e519524SHoward Hinnant        : __m_(__m) {__m_.lock();}
9586dd28a5SLouis Dionne
9686dd28a5SLouis Dionne    _LIBCPP_NODISCARD_EXT _LIBCPP_INLINE_VISIBILITY
977865b2e9SEric Fiselier    lock_guard(mutex_type& __m, adopt_lock_t) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
983e519524SHoward Hinnant        : __m_(__m) {}
99f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY
1007865b2e9SEric Fiselier    ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();}
1013e519524SHoward Hinnant
1023e519524SHoward Hinnantprivate:
103d7d70601SArthur O'Dwyer    lock_guard(lock_guard const&) = delete;
104d7d70601SArthur O'Dwyer    lock_guard& operator=(lock_guard const&) = delete;
1053e519524SHoward Hinnant};
1063e519524SHoward Hinnant
1073e519524SHoward Hinnanttemplate <class _Mutex>
108e2f2d1edSEric Fiselierclass _LIBCPP_TEMPLATE_VIS unique_lock
1093e519524SHoward Hinnant{
1103e519524SHoward Hinnantpublic:
1113e519524SHoward Hinnant    typedef _Mutex mutex_type;
1123e519524SHoward Hinnant
1133e519524SHoward Hinnantprivate:
1143e519524SHoward Hinnant    mutex_type* __m_;
1153e519524SHoward Hinnant    bool __owns_;
1163e519524SHoward Hinnant
1173e519524SHoward Hinnantpublic:
118f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY
11902e610efSHoward Hinnant    unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
120f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY
1213e519524SHoward Hinnant    explicit unique_lock(mutex_type& __m)
1223126c881SMarshall Clow        : __m_(_VSTD::addressof(__m)), __owns_(true) {__m_->lock();}
123f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY
12402e610efSHoward Hinnant    unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
1253126c881SMarshall Clow        : __m_(_VSTD::addressof(__m)), __owns_(false) {}
126f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY
1273e519524SHoward Hinnant    unique_lock(mutex_type& __m, try_to_lock_t)
1283126c881SMarshall Clow        : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock()) {}
129f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY
1303e519524SHoward Hinnant    unique_lock(mutex_type& __m, adopt_lock_t)
1313126c881SMarshall Clow        : __m_(_VSTD::addressof(__m)), __owns_(true) {}
1323e519524SHoward Hinnant    template <class _Clock, class _Duration>
133f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY
1343e519524SHoward Hinnant        unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t)
1353126c881SMarshall Clow            : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_until(__t)) {}
1363e519524SHoward Hinnant    template <class _Rep, class _Period>
137f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY
1383e519524SHoward Hinnant        unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
1393126c881SMarshall Clow            : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_for(__d)) {}
140f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY
1413e519524SHoward Hinnant    ~unique_lock()
1423e519524SHoward Hinnant    {
1433e519524SHoward Hinnant        if (__owns_)
1443e519524SHoward Hinnant            __m_->unlock();
1453e519524SHoward Hinnant    }
1463e519524SHoward Hinnant
147feb80aa9SNikolas Klauser    unique_lock(unique_lock const&) = delete;
148feb80aa9SNikolas Klauser    unique_lock& operator=(unique_lock const&) = delete;
1493e519524SHoward Hinnant
150f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY
15102e610efSHoward Hinnant    unique_lock(unique_lock&& __u) _NOEXCEPT
1523e519524SHoward Hinnant        : __m_(__u.__m_), __owns_(__u.__owns_)
1533e519524SHoward Hinnant        {__u.__m_ = nullptr; __u.__owns_ = false;}
154f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY
15502e610efSHoward Hinnant    unique_lock& operator=(unique_lock&& __u) _NOEXCEPT
1563e519524SHoward Hinnant        {
1573e519524SHoward Hinnant            if (__owns_)
1583e519524SHoward Hinnant                __m_->unlock();
1593e519524SHoward Hinnant            __m_ = __u.__m_;
1603e519524SHoward Hinnant            __owns_ = __u.__owns_;
1613e519524SHoward Hinnant            __u.__m_ = nullptr;
1623e519524SHoward Hinnant            __u.__owns_ = false;
1633e519524SHoward Hinnant            return *this;
1643e519524SHoward Hinnant        }
1656fd5c650SHoward Hinnant
1663e519524SHoward Hinnant    void lock();
1673e519524SHoward Hinnant    bool try_lock();
1683e519524SHoward Hinnant
1693e519524SHoward Hinnant    template <class _Rep, class _Period>
1703e519524SHoward Hinnant        bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
1713e519524SHoward Hinnant    template <class _Clock, class _Duration>
1723e519524SHoward Hinnant        bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
1733e519524SHoward Hinnant
1743e519524SHoward Hinnant    void unlock();
1753e519524SHoward Hinnant
176f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY
17702e610efSHoward Hinnant    void swap(unique_lock& __u) _NOEXCEPT
1783e519524SHoward Hinnant    {
179ce48a113SHoward Hinnant        _VSTD::swap(__m_, __u.__m_);
180ce48a113SHoward Hinnant        _VSTD::swap(__owns_, __u.__owns_);
1813e519524SHoward Hinnant    }
182f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY
18302e610efSHoward Hinnant    mutex_type* release() _NOEXCEPT
1843e519524SHoward Hinnant    {
1853e519524SHoward Hinnant        mutex_type* __m = __m_;
1863e519524SHoward Hinnant        __m_ = nullptr;
1873e519524SHoward Hinnant        __owns_ = false;
1883e519524SHoward Hinnant        return __m;
1893e519524SHoward Hinnant    }
1903e519524SHoward Hinnant
191f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY
19202e610efSHoward Hinnant    bool owns_lock() const _NOEXCEPT {return __owns_;}
193f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY
194317e92a3SArthur O'Dwyer    explicit operator bool() const _NOEXCEPT {return __owns_;}
195f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY
19602e610efSHoward Hinnant    mutex_type* mutex() const _NOEXCEPT {return __m_;}
1973e519524SHoward Hinnant};
1983e519524SHoward Hinnant
1993e519524SHoward Hinnanttemplate <class _Mutex>
2003e519524SHoward Hinnantvoid
2013e519524SHoward Hinnantunique_lock<_Mutex>::lock()
2023e519524SHoward Hinnant{
2033e519524SHoward Hinnant    if (__m_ == nullptr)
2043e519524SHoward Hinnant        __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
2053e519524SHoward Hinnant    if (__owns_)
2063e519524SHoward Hinnant        __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
2073e519524SHoward Hinnant    __m_->lock();
2083e519524SHoward Hinnant    __owns_ = true;
2093e519524SHoward Hinnant}
2103e519524SHoward Hinnant
2113e519524SHoward Hinnanttemplate <class _Mutex>
2123e519524SHoward Hinnantbool
2133e519524SHoward Hinnantunique_lock<_Mutex>::try_lock()
2143e519524SHoward Hinnant{
2153e519524SHoward Hinnant    if (__m_ == nullptr)
2163e519524SHoward Hinnant        __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
2173e519524SHoward Hinnant    if (__owns_)
2183e519524SHoward Hinnant        __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
2193e519524SHoward Hinnant    __owns_ = __m_->try_lock();
2203e519524SHoward Hinnant    return __owns_;
2213e519524SHoward Hinnant}
2223e519524SHoward Hinnant
2233e519524SHoward Hinnanttemplate <class _Mutex>
2243e519524SHoward Hinnanttemplate <class _Rep, class _Period>
2253e519524SHoward Hinnantbool
2263e519524SHoward Hinnantunique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
2273e519524SHoward Hinnant{
2283e519524SHoward Hinnant    if (__m_ == nullptr)
2293e519524SHoward Hinnant        __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
2303e519524SHoward Hinnant    if (__owns_)
2313e519524SHoward Hinnant        __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
2323e519524SHoward Hinnant    __owns_ = __m_->try_lock_for(__d);
2333e519524SHoward Hinnant    return __owns_;
2343e519524SHoward Hinnant}
2353e519524SHoward Hinnant
2363e519524SHoward Hinnanttemplate <class _Mutex>
2373e519524SHoward Hinnanttemplate <class _Clock, class _Duration>
2383e519524SHoward Hinnantbool
2393e519524SHoward Hinnantunique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
2403e519524SHoward Hinnant{
2413e519524SHoward Hinnant    if (__m_ == nullptr)
2423e519524SHoward Hinnant        __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
2433e519524SHoward Hinnant    if (__owns_)
2443e519524SHoward Hinnant        __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
2453e519524SHoward Hinnant    __owns_ = __m_->try_lock_until(__t);
2463e519524SHoward Hinnant    return __owns_;
2473e519524SHoward Hinnant}
2483e519524SHoward Hinnant
2493e519524SHoward Hinnanttemplate <class _Mutex>
2503e519524SHoward Hinnantvoid
2513e519524SHoward Hinnantunique_lock<_Mutex>::unlock()
2523e519524SHoward Hinnant{
2533e519524SHoward Hinnant    if (!__owns_)
2543e519524SHoward Hinnant        __throw_system_error(EPERM, "unique_lock::unlock: not locked");
2553e519524SHoward Hinnant    __m_->unlock();
2563e519524SHoward Hinnant    __owns_ = false;
2573e519524SHoward Hinnant}
2583e519524SHoward Hinnant
2593e519524SHoward Hinnanttemplate <class _Mutex>
260f5ab703fSHoward Hinnantinline _LIBCPP_INLINE_VISIBILITY
2613e519524SHoward Hinnantvoid
26202e610efSHoward Hinnantswap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT
26302e610efSHoward Hinnant    {__x.swap(__y);}
2643e519524SHoward Hinnant
265ce81aed4SMarshall Clow//enum class cv_status
266ce81aed4SMarshall Clow_LIBCPP_DECLARE_STRONG_ENUM(cv_status)
2673e519524SHoward Hinnant{
2683e519524SHoward Hinnant    no_timeout,
2693e519524SHoward Hinnant    timeout
2703e519524SHoward Hinnant};
271ce81aed4SMarshall Clow_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status)
2723e519524SHoward Hinnant
2736e41256fSHoward Hinnantclass _LIBCPP_TYPE_VIS condition_variable
2743e519524SHoward Hinnant{
275816739caSMarshall Clow    __libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;
2763e519524SHoward Hinnantpublic:
277f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY
2788cedf04aSEric Fiselier    _LIBCPP_CONSTEXPR condition_variable() _NOEXCEPT = default;
2798cedf04aSEric Fiselier
2808cedf04aSEric Fiselier#ifdef _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
2818cedf04aSEric Fiselier    ~condition_variable() = default;
282bfa7990bSHoward Hinnant#else
2833e519524SHoward Hinnant    ~condition_variable();
2848cedf04aSEric Fiselier#endif
2853e519524SHoward Hinnant
2868cedf04aSEric Fiselier    condition_variable(const condition_variable&) = delete;
2878cedf04aSEric Fiselier    condition_variable& operator=(const condition_variable&) = delete;
2883e519524SHoward Hinnant
28945c663dbSHoward Hinnant    void notify_one() _NOEXCEPT;
29045c663dbSHoward Hinnant    void notify_all() _NOEXCEPT;
2913e519524SHoward Hinnant
2921641a7c1SMarshall Clow    void wait(unique_lock<mutex>& __lk) _NOEXCEPT;
2933e519524SHoward Hinnant    template <class _Predicate>
294bda3c7dfSShoaib Meenai        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
2953e519524SHoward Hinnant        void wait(unique_lock<mutex>& __lk, _Predicate __pred);
2963e519524SHoward Hinnant
2973e519524SHoward Hinnant    template <class _Clock, class _Duration>
298bda3c7dfSShoaib Meenai        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
2993e519524SHoward Hinnant        cv_status
3003e519524SHoward Hinnant        wait_until(unique_lock<mutex>& __lk,
3013e519524SHoward Hinnant                   const chrono::time_point<_Clock, _Duration>& __t);
3023e519524SHoward Hinnant
3033e519524SHoward Hinnant    template <class _Clock, class _Duration, class _Predicate>
304bda3c7dfSShoaib Meenai        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
3053e519524SHoward Hinnant        bool
3063e519524SHoward Hinnant        wait_until(unique_lock<mutex>& __lk,
3073e519524SHoward Hinnant                   const chrono::time_point<_Clock, _Duration>& __t,
3083e519524SHoward Hinnant                   _Predicate __pred);
3093e519524SHoward Hinnant
3103e519524SHoward Hinnant    template <class _Rep, class _Period>
311bda3c7dfSShoaib Meenai        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
3123e519524SHoward Hinnant        cv_status
3133e519524SHoward Hinnant        wait_for(unique_lock<mutex>& __lk,
3143e519524SHoward Hinnant                 const chrono::duration<_Rep, _Period>& __d);
3153e519524SHoward Hinnant
3163e519524SHoward Hinnant    template <class _Rep, class _Period, class _Predicate>
3173e519524SHoward Hinnant        bool
318906c872dSEvgeniy Stepanov        _LIBCPP_INLINE_VISIBILITY
3193e519524SHoward Hinnant        wait_for(unique_lock<mutex>& __lk,
3203e519524SHoward Hinnant                 const chrono::duration<_Rep, _Period>& __d,
3213e519524SHoward Hinnant                 _Predicate __pred);
3223e519524SHoward Hinnant
323c7e4239fSAsiri Rathnayake    typedef __libcpp_condvar_t* native_handle_type;
324f5ab703fSHoward Hinnant    _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
3253e519524SHoward Hinnant
3263e519524SHoward Hinnantprivate:
3273e519524SHoward Hinnant    void __do_timed_wait(unique_lock<mutex>& __lk,
3281641a7c1SMarshall Clow       chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;
32985e26f56SDan Albert#if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
33085e26f56SDan Albert    void __do_timed_wait(unique_lock<mutex>& __lk,
33185e26f56SDan Albert       chrono::time_point<chrono::steady_clock, chrono::nanoseconds>) _NOEXCEPT;
33285e26f56SDan Albert#endif
33385e26f56SDan Albert    template <class _Clock>
33485e26f56SDan Albert    void __do_timed_wait(unique_lock<mutex>& __lk,
33585e26f56SDan Albert       chrono::time_point<_Clock, chrono::nanoseconds>) _NOEXCEPT;
3363e519524SHoward Hinnant};
337b3fcc67fSJonathan Roelofs#endif // !_LIBCPP_HAS_NO_THREADS
3383e519524SHoward Hinnant
33985e26f56SDan Alberttemplate <class _Rep, class _Period>
340f5ab703fSHoward Hinnantinline _LIBCPP_INLINE_VISIBILITY
341*4887d047SNikolas Klauser__enable_if_t<is_floating_point<_Rep>::value, chrono::nanoseconds>
34285e26f56SDan Albert__safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d)
3433e519524SHoward Hinnant{
3443e519524SHoward Hinnant    using namespace chrono;
34585e26f56SDan Albert    using __ratio = ratio_divide<_Period, nano>;
34685e26f56SDan Albert    using __ns_rep = nanoseconds::rep;
34785e26f56SDan Albert    _Rep __result_float = __d.count() * __ratio::num / __ratio::den;
34885e26f56SDan Albert
34985e26f56SDan Albert    _Rep __result_max = numeric_limits<__ns_rep>::max();
35085e26f56SDan Albert    if (__result_float >= __result_max) {
35185e26f56SDan Albert        return nanoseconds::max();
35285e26f56SDan Albert    }
35385e26f56SDan Albert
35485e26f56SDan Albert    _Rep __result_min = numeric_limits<__ns_rep>::min();
35585e26f56SDan Albert    if (__result_float <= __result_min) {
35685e26f56SDan Albert        return nanoseconds::min();
35785e26f56SDan Albert    }
35885e26f56SDan Albert
35985e26f56SDan Albert    return nanoseconds(static_cast<__ns_rep>(__result_float));
36085e26f56SDan Albert}
36185e26f56SDan Albert
36285e26f56SDan Alberttemplate <class _Rep, class _Period>
36385e26f56SDan Albertinline _LIBCPP_INLINE_VISIBILITY
364*4887d047SNikolas Klauser__enable_if_t<!is_floating_point<_Rep>::value, chrono::nanoseconds>
36585e26f56SDan Albert__safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d)
36685e26f56SDan Albert{
36785e26f56SDan Albert    using namespace chrono;
36885e26f56SDan Albert    if (__d.count() == 0) {
36985e26f56SDan Albert        return nanoseconds(0);
37085e26f56SDan Albert    }
37185e26f56SDan Albert
37285e26f56SDan Albert    using __ratio = ratio_divide<_Period, nano>;
37385e26f56SDan Albert    using __ns_rep = nanoseconds::rep;
374d586f92cSArthur O'Dwyer    __ns_rep __result_max = numeric_limits<__ns_rep>::max();
37585e26f56SDan Albert    if (__d.count() > 0 && __d.count() > __result_max / __ratio::num) {
37685e26f56SDan Albert        return nanoseconds::max();
37785e26f56SDan Albert    }
37885e26f56SDan Albert
379d586f92cSArthur O'Dwyer    __ns_rep __result_min = numeric_limits<__ns_rep>::min();
38085e26f56SDan Albert    if (__d.count() < 0 && __d.count() < __result_min / __ratio::num) {
38185e26f56SDan Albert        return nanoseconds::min();
38285e26f56SDan Albert    }
38385e26f56SDan Albert
38485e26f56SDan Albert    __ns_rep __result = __d.count() * __ratio::num / __ratio::den;
38585e26f56SDan Albert    if (__result == 0) {
38685e26f56SDan Albert        return nanoseconds(1);
38785e26f56SDan Albert    }
38885e26f56SDan Albert
38985e26f56SDan Albert    return nanoseconds(__result);
3903e519524SHoward Hinnant}
3913e519524SHoward Hinnant
392b3fcc67fSJonathan Roelofs#ifndef _LIBCPP_HAS_NO_THREADS
3933e519524SHoward Hinnanttemplate <class _Predicate>
3943e519524SHoward Hinnantvoid
3953e519524SHoward Hinnantcondition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
3963e519524SHoward Hinnant{
3973e519524SHoward Hinnant    while (!__pred())
3983e519524SHoward Hinnant        wait(__lk);
3993e519524SHoward Hinnant}
4003e519524SHoward Hinnant
4013e519524SHoward Hinnanttemplate <class _Clock, class _Duration>
4023e519524SHoward Hinnantcv_status
4033e519524SHoward Hinnantcondition_variable::wait_until(unique_lock<mutex>& __lk,
4043e519524SHoward Hinnant                               const chrono::time_point<_Clock, _Duration>& __t)
4053e519524SHoward Hinnant{
4063e519524SHoward Hinnant    using namespace chrono;
40785e26f56SDan Albert    using __clock_tp_ns = time_point<_Clock, nanoseconds>;
40885e26f56SDan Albert
40985e26f56SDan Albert    typename _Clock::time_point __now = _Clock::now();
41085e26f56SDan Albert    if (__t <= __now)
41185e26f56SDan Albert        return cv_status::timeout;
41285e26f56SDan Albert
413781c476cSArthur O'Dwyer    __clock_tp_ns __t_ns = __clock_tp_ns(_VSTD::__safe_nanosecond_cast(__t.time_since_epoch()));
41485e26f56SDan Albert
41585e26f56SDan Albert    __do_timed_wait(__lk, __t_ns);
4163e519524SHoward Hinnant    return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
4173e519524SHoward Hinnant}
4183e519524SHoward Hinnant
4193e519524SHoward Hinnanttemplate <class _Clock, class _Duration, class _Predicate>
4203e519524SHoward Hinnantbool
4213e519524SHoward Hinnantcondition_variable::wait_until(unique_lock<mutex>& __lk,
4223e519524SHoward Hinnant                   const chrono::time_point<_Clock, _Duration>& __t,
4233e519524SHoward Hinnant                   _Predicate __pred)
4243e519524SHoward Hinnant{
4253e519524SHoward Hinnant    while (!__pred())
4263e519524SHoward Hinnant    {
4273e519524SHoward Hinnant        if (wait_until(__lk, __t) == cv_status::timeout)
4283e519524SHoward Hinnant            return __pred();
4293e519524SHoward Hinnant    }
4303e519524SHoward Hinnant    return true;
4313e519524SHoward Hinnant}
4323e519524SHoward Hinnant
4333e519524SHoward Hinnanttemplate <class _Rep, class _Period>
4343e519524SHoward Hinnantcv_status
4353e519524SHoward Hinnantcondition_variable::wait_for(unique_lock<mutex>& __lk,
4363e519524SHoward Hinnant                             const chrono::duration<_Rep, _Period>& __d)
4373e519524SHoward Hinnant{
4383e519524SHoward Hinnant    using namespace chrono;
439aad745a0SHoward Hinnant    if (__d <= __d.zero())
440aad745a0SHoward Hinnant        return cv_status::timeout;
44185e26f56SDan Albert    using __ns_rep = nanoseconds::rep;
4423dc6455fSHoward Hinnant    steady_clock::time_point __c_now = steady_clock::now();
44385e26f56SDan Albert
44485e26f56SDan Albert#if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
44585e26f56SDan Albert    using __clock_tp_ns = time_point<steady_clock, nanoseconds>;
446781c476cSArthur O'Dwyer    __ns_rep __now_count_ns = _VSTD::__safe_nanosecond_cast(__c_now.time_since_epoch()).count();
44785e26f56SDan Albert#else
44885e26f56SDan Albert    using __clock_tp_ns = time_point<system_clock, nanoseconds>;
449781c476cSArthur O'Dwyer    __ns_rep __now_count_ns = _VSTD::__safe_nanosecond_cast(system_clock::now().time_since_epoch()).count();
45085e26f56SDan Albert#endif
45185e26f56SDan Albert
452781c476cSArthur O'Dwyer    __ns_rep __d_ns_count = _VSTD::__safe_nanosecond_cast(__d).count();
45385e26f56SDan Albert
45485e26f56SDan Albert    if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) {
45585e26f56SDan Albert        __do_timed_wait(__lk, __clock_tp_ns::max());
45685e26f56SDan Albert    } else {
45785e26f56SDan Albert        __do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count)));
45885e26f56SDan Albert    }
45985e26f56SDan Albert
4603dc6455fSHoward Hinnant    return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
4613e519524SHoward Hinnant                                                 cv_status::timeout;
4623e519524SHoward Hinnant}
4633e519524SHoward Hinnant
4643e519524SHoward Hinnanttemplate <class _Rep, class _Period, class _Predicate>
465906c872dSEvgeniy Stepanovinline
4663e519524SHoward Hinnantbool
4673e519524SHoward Hinnantcondition_variable::wait_for(unique_lock<mutex>& __lk,
4683e519524SHoward Hinnant                             const chrono::duration<_Rep, _Period>& __d,
4693e519524SHoward Hinnant                             _Predicate __pred)
4703e519524SHoward Hinnant{
4713dc6455fSHoward Hinnant    return wait_until(__lk, chrono::steady_clock::now() + __d,
472ce48a113SHoward Hinnant                      _VSTD::move(__pred));
4733e519524SHoward Hinnant}
4743e519524SHoward Hinnant
47585e26f56SDan Albert#if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
47685e26f56SDan Albertinline
47785e26f56SDan Albertvoid
47885e26f56SDan Albertcondition_variable::__do_timed_wait(unique_lock<mutex>& __lk,
47985e26f56SDan Albert     chrono::time_point<chrono::steady_clock, chrono::nanoseconds> __tp) _NOEXCEPT
48085e26f56SDan Albert{
48185e26f56SDan Albert    using namespace chrono;
48285e26f56SDan Albert    if (!__lk.owns_lock())
48385e26f56SDan Albert        __throw_system_error(EPERM,
48485e26f56SDan Albert                            "condition_variable::timed wait: mutex not locked");
48585e26f56SDan Albert    nanoseconds __d = __tp.time_since_epoch();
48685e26f56SDan Albert    timespec __ts;
48785e26f56SDan Albert    seconds __s = duration_cast<seconds>(__d);
48885e26f56SDan Albert    using __ts_sec = decltype(__ts.tv_sec);
48985e26f56SDan Albert    const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max();
49085e26f56SDan Albert    if (__s.count() < __ts_sec_max)
49185e26f56SDan Albert    {
49285e26f56SDan Albert        __ts.tv_sec = static_cast<__ts_sec>(__s.count());
49385e26f56SDan Albert        __ts.tv_nsec = (__d - __s).count();
49485e26f56SDan Albert    }
49585e26f56SDan Albert    else
49685e26f56SDan Albert    {
49785e26f56SDan Albert        __ts.tv_sec = __ts_sec_max;
49885e26f56SDan Albert        __ts.tv_nsec = giga::num - 1;
49985e26f56SDan Albert    }
50085e26f56SDan Albert    int __ec = pthread_cond_clockwait(&__cv_, __lk.mutex()->native_handle(), CLOCK_MONOTONIC, &__ts);
50185e26f56SDan Albert    if (__ec != 0 && __ec != ETIMEDOUT)
50285e26f56SDan Albert        __throw_system_error(__ec, "condition_variable timed_wait failed");
50385e26f56SDan Albert}
50485e26f56SDan Albert#endif // _LIBCPP_HAS_COND_CLOCKWAIT
50585e26f56SDan Albert
50685e26f56SDan Alberttemplate <class _Clock>
50785e26f56SDan Albertinline
50885e26f56SDan Albertvoid
50985e26f56SDan Albertcondition_variable::__do_timed_wait(unique_lock<mutex>& __lk,
51085e26f56SDan Albert     chrono::time_point<_Clock, chrono::nanoseconds> __tp) _NOEXCEPT
51185e26f56SDan Albert{
51285e26f56SDan Albert    wait_for(__lk, __tp - _Clock::now());
51385e26f56SDan Albert}
51485e26f56SDan Albert
515b3fcc67fSJonathan Roelofs#endif // !_LIBCPP_HAS_NO_THREADS
516b3fcc67fSJonathan Roelofs
5173e519524SHoward Hinnant_LIBCPP_END_NAMESPACE_STD
5183e519524SHoward Hinnant
519a016efb1SEric Fiselier_LIBCPP_POP_MACROS
520a016efb1SEric Fiselier
5213e519524SHoward Hinnant#endif // _LIBCPP___MUTEX_BASE
522