1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef _LIBCPP___MUTEX_BASE
11#define _LIBCPP___MUTEX_BASE
12
13#include <__chrono/duration.h>
14#include <__chrono/steady_clock.h>
15#include <__chrono/system_clock.h>
16#include <__chrono/time_point.h>
17#include <__config>
18#include <__threading_support>
19#include <ratio>
20#include <system_error>
21#include <time.h>
22
23#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
24#  pragma GCC system_header
25#endif
26
27_LIBCPP_PUSH_MACROS
28#include <__undef_macros>
29
30
31_LIBCPP_BEGIN_NAMESPACE_STD
32
33#ifndef _LIBCPP_HAS_NO_THREADS
34
35class _LIBCPP_TYPE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mutex
36{
37    __libcpp_mutex_t __m_ = _LIBCPP_MUTEX_INITIALIZER;
38
39public:
40    _LIBCPP_INLINE_VISIBILITY
41    _LIBCPP_CONSTEXPR mutex() = default;
42
43    mutex(const mutex&) = delete;
44    mutex& operator=(const mutex&) = delete;
45
46#if defined(_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION)
47    ~mutex() = default;
48#else
49    ~mutex() _NOEXCEPT;
50#endif
51
52    void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability());
53    bool try_lock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
54    void unlock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
55
56    typedef __libcpp_mutex_t* native_handle_type;
57    _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
58};
59
60static_assert(is_nothrow_default_constructible<mutex>::value,
61              "the default constructor for std::mutex must be nothrow");
62
63struct _LIBCPP_TYPE_VIS defer_lock_t { explicit defer_lock_t() = default; };
64struct _LIBCPP_TYPE_VIS try_to_lock_t { explicit try_to_lock_t() = default; };
65struct _LIBCPP_TYPE_VIS adopt_lock_t { explicit adopt_lock_t() = default; };
66
67#if defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY)
68
69extern _LIBCPP_EXPORTED_FROM_ABI const defer_lock_t  defer_lock;
70extern _LIBCPP_EXPORTED_FROM_ABI const try_to_lock_t try_to_lock;
71extern _LIBCPP_EXPORTED_FROM_ABI const adopt_lock_t  adopt_lock;
72
73#else
74
75/* inline */ constexpr defer_lock_t  defer_lock  = defer_lock_t();
76/* inline */ constexpr try_to_lock_t try_to_lock = try_to_lock_t();
77/* inline */ constexpr adopt_lock_t  adopt_lock  = adopt_lock_t();
78
79#endif
80
81template <class _Mutex>
82class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable)
83lock_guard
84{
85public:
86    typedef _Mutex mutex_type;
87
88private:
89    mutex_type& __m_;
90public:
91
92    _LIBCPP_NODISCARD_EXT _LIBCPP_INLINE_VISIBILITY
93    explicit lock_guard(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m))
94        : __m_(__m) {__m_.lock();}
95
96    _LIBCPP_NODISCARD_EXT _LIBCPP_INLINE_VISIBILITY
97    lock_guard(mutex_type& __m, adopt_lock_t) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
98        : __m_(__m) {}
99    _LIBCPP_INLINE_VISIBILITY
100    ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();}
101
102private:
103    lock_guard(lock_guard const&) = delete;
104    lock_guard& operator=(lock_guard const&) = delete;
105};
106
107template <class _Mutex>
108class _LIBCPP_TEMPLATE_VIS unique_lock
109{
110public:
111    typedef _Mutex mutex_type;
112
113private:
114    mutex_type* __m_;
115    bool __owns_;
116
117public:
118    _LIBCPP_INLINE_VISIBILITY
119    unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
120    _LIBCPP_INLINE_VISIBILITY
121    explicit unique_lock(mutex_type& __m)
122        : __m_(_VSTD::addressof(__m)), __owns_(true) {__m_->lock();}
123    _LIBCPP_INLINE_VISIBILITY
124    unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
125        : __m_(_VSTD::addressof(__m)), __owns_(false) {}
126    _LIBCPP_INLINE_VISIBILITY
127    unique_lock(mutex_type& __m, try_to_lock_t)
128        : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock()) {}
129    _LIBCPP_INLINE_VISIBILITY
130    unique_lock(mutex_type& __m, adopt_lock_t)
131        : __m_(_VSTD::addressof(__m)), __owns_(true) {}
132    template <class _Clock, class _Duration>
133    _LIBCPP_INLINE_VISIBILITY
134        unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t)
135            : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_until(__t)) {}
136    template <class _Rep, class _Period>
137    _LIBCPP_INLINE_VISIBILITY
138        unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
139            : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_for(__d)) {}
140    _LIBCPP_INLINE_VISIBILITY
141    ~unique_lock()
142    {
143        if (__owns_)
144            __m_->unlock();
145    }
146
147    unique_lock(unique_lock const&) = delete;
148    unique_lock& operator=(unique_lock const&) = delete;
149
150    _LIBCPP_INLINE_VISIBILITY
151    unique_lock(unique_lock&& __u) _NOEXCEPT
152        : __m_(__u.__m_), __owns_(__u.__owns_)
153        {__u.__m_ = nullptr; __u.__owns_ = false;}
154    _LIBCPP_INLINE_VISIBILITY
155    unique_lock& operator=(unique_lock&& __u) _NOEXCEPT
156        {
157            if (__owns_)
158                __m_->unlock();
159            __m_ = __u.__m_;
160            __owns_ = __u.__owns_;
161            __u.__m_ = nullptr;
162            __u.__owns_ = false;
163            return *this;
164        }
165
166    void lock();
167    bool try_lock();
168
169    template <class _Rep, class _Period>
170        bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
171    template <class _Clock, class _Duration>
172        bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
173
174    void unlock();
175
176    _LIBCPP_INLINE_VISIBILITY
177    void swap(unique_lock& __u) _NOEXCEPT
178    {
179        _VSTD::swap(__m_, __u.__m_);
180        _VSTD::swap(__owns_, __u.__owns_);
181    }
182    _LIBCPP_INLINE_VISIBILITY
183    mutex_type* release() _NOEXCEPT
184    {
185        mutex_type* __m = __m_;
186        __m_ = nullptr;
187        __owns_ = false;
188        return __m;
189    }
190
191    _LIBCPP_INLINE_VISIBILITY
192    bool owns_lock() const _NOEXCEPT {return __owns_;}
193    _LIBCPP_INLINE_VISIBILITY
194    explicit operator bool() const _NOEXCEPT {return __owns_;}
195    _LIBCPP_INLINE_VISIBILITY
196    mutex_type* mutex() const _NOEXCEPT {return __m_;}
197};
198
199template <class _Mutex>
200void
201unique_lock<_Mutex>::lock()
202{
203    if (__m_ == nullptr)
204        __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
205    if (__owns_)
206        __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
207    __m_->lock();
208    __owns_ = true;
209}
210
211template <class _Mutex>
212bool
213unique_lock<_Mutex>::try_lock()
214{
215    if (__m_ == nullptr)
216        __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
217    if (__owns_)
218        __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
219    __owns_ = __m_->try_lock();
220    return __owns_;
221}
222
223template <class _Mutex>
224template <class _Rep, class _Period>
225bool
226unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
227{
228    if (__m_ == nullptr)
229        __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
230    if (__owns_)
231        __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
232    __owns_ = __m_->try_lock_for(__d);
233    return __owns_;
234}
235
236template <class _Mutex>
237template <class _Clock, class _Duration>
238bool
239unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
240{
241    if (__m_ == nullptr)
242        __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
243    if (__owns_)
244        __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
245    __owns_ = __m_->try_lock_until(__t);
246    return __owns_;
247}
248
249template <class _Mutex>
250void
251unique_lock<_Mutex>::unlock()
252{
253    if (!__owns_)
254        __throw_system_error(EPERM, "unique_lock::unlock: not locked");
255    __m_->unlock();
256    __owns_ = false;
257}
258
259template <class _Mutex>
260inline _LIBCPP_INLINE_VISIBILITY
261void
262swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT
263    {__x.swap(__y);}
264
265//enum class cv_status
266_LIBCPP_DECLARE_STRONG_ENUM(cv_status)
267{
268    no_timeout,
269    timeout
270};
271_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status)
272
273class _LIBCPP_TYPE_VIS condition_variable
274{
275    __libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;
276public:
277    _LIBCPP_INLINE_VISIBILITY
278    _LIBCPP_CONSTEXPR condition_variable() _NOEXCEPT = default;
279
280#ifdef _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
281    ~condition_variable() = default;
282#else
283    ~condition_variable();
284#endif
285
286    condition_variable(const condition_variable&) = delete;
287    condition_variable& operator=(const condition_variable&) = delete;
288
289    void notify_one() _NOEXCEPT;
290    void notify_all() _NOEXCEPT;
291
292    void wait(unique_lock<mutex>& __lk) _NOEXCEPT;
293    template <class _Predicate>
294        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
295        void wait(unique_lock<mutex>& __lk, _Predicate __pred);
296
297    template <class _Clock, class _Duration>
298        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
299        cv_status
300        wait_until(unique_lock<mutex>& __lk,
301                   const chrono::time_point<_Clock, _Duration>& __t);
302
303    template <class _Clock, class _Duration, class _Predicate>
304        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
305        bool
306        wait_until(unique_lock<mutex>& __lk,
307                   const chrono::time_point<_Clock, _Duration>& __t,
308                   _Predicate __pred);
309
310    template <class _Rep, class _Period>
311        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
312        cv_status
313        wait_for(unique_lock<mutex>& __lk,
314                 const chrono::duration<_Rep, _Period>& __d);
315
316    template <class _Rep, class _Period, class _Predicate>
317        bool
318        _LIBCPP_INLINE_VISIBILITY
319        wait_for(unique_lock<mutex>& __lk,
320                 const chrono::duration<_Rep, _Period>& __d,
321                 _Predicate __pred);
322
323    typedef __libcpp_condvar_t* native_handle_type;
324    _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
325
326private:
327    void __do_timed_wait(unique_lock<mutex>& __lk,
328       chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;
329#if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
330    void __do_timed_wait(unique_lock<mutex>& __lk,
331       chrono::time_point<chrono::steady_clock, chrono::nanoseconds>) _NOEXCEPT;
332#endif
333    template <class _Clock>
334    void __do_timed_wait(unique_lock<mutex>& __lk,
335       chrono::time_point<_Clock, chrono::nanoseconds>) _NOEXCEPT;
336};
337#endif // !_LIBCPP_HAS_NO_THREADS
338
339template <class _Rep, class _Period>
340inline _LIBCPP_INLINE_VISIBILITY
341typename enable_if
342<
343    is_floating_point<_Rep>::value,
344    chrono::nanoseconds
345>::type
346__safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d)
347{
348    using namespace chrono;
349    using __ratio = ratio_divide<_Period, nano>;
350    using __ns_rep = nanoseconds::rep;
351    _Rep __result_float = __d.count() * __ratio::num / __ratio::den;
352
353    _Rep __result_max = numeric_limits<__ns_rep>::max();
354    if (__result_float >= __result_max) {
355        return nanoseconds::max();
356    }
357
358    _Rep __result_min = numeric_limits<__ns_rep>::min();
359    if (__result_float <= __result_min) {
360        return nanoseconds::min();
361    }
362
363    return nanoseconds(static_cast<__ns_rep>(__result_float));
364}
365
366template <class _Rep, class _Period>
367inline _LIBCPP_INLINE_VISIBILITY
368typename enable_if
369<
370    !is_floating_point<_Rep>::value,
371    chrono::nanoseconds
372>::type
373__safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d)
374{
375    using namespace chrono;
376    if (__d.count() == 0) {
377        return nanoseconds(0);
378    }
379
380    using __ratio = ratio_divide<_Period, nano>;
381    using __ns_rep = nanoseconds::rep;
382    __ns_rep __result_max = numeric_limits<__ns_rep>::max();
383    if (__d.count() > 0 && __d.count() > __result_max / __ratio::num) {
384        return nanoseconds::max();
385    }
386
387    __ns_rep __result_min = numeric_limits<__ns_rep>::min();
388    if (__d.count() < 0 && __d.count() < __result_min / __ratio::num) {
389        return nanoseconds::min();
390    }
391
392    __ns_rep __result = __d.count() * __ratio::num / __ratio::den;
393    if (__result == 0) {
394        return nanoseconds(1);
395    }
396
397    return nanoseconds(__result);
398}
399
400#ifndef _LIBCPP_HAS_NO_THREADS
401template <class _Predicate>
402void
403condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
404{
405    while (!__pred())
406        wait(__lk);
407}
408
409template <class _Clock, class _Duration>
410cv_status
411condition_variable::wait_until(unique_lock<mutex>& __lk,
412                               const chrono::time_point<_Clock, _Duration>& __t)
413{
414    using namespace chrono;
415    using __clock_tp_ns = time_point<_Clock, nanoseconds>;
416
417    typename _Clock::time_point __now = _Clock::now();
418    if (__t <= __now)
419        return cv_status::timeout;
420
421    __clock_tp_ns __t_ns = __clock_tp_ns(_VSTD::__safe_nanosecond_cast(__t.time_since_epoch()));
422
423    __do_timed_wait(__lk, __t_ns);
424    return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
425}
426
427template <class _Clock, class _Duration, class _Predicate>
428bool
429condition_variable::wait_until(unique_lock<mutex>& __lk,
430                   const chrono::time_point<_Clock, _Duration>& __t,
431                   _Predicate __pred)
432{
433    while (!__pred())
434    {
435        if (wait_until(__lk, __t) == cv_status::timeout)
436            return __pred();
437    }
438    return true;
439}
440
441template <class _Rep, class _Period>
442cv_status
443condition_variable::wait_for(unique_lock<mutex>& __lk,
444                             const chrono::duration<_Rep, _Period>& __d)
445{
446    using namespace chrono;
447    if (__d <= __d.zero())
448        return cv_status::timeout;
449    using __ns_rep = nanoseconds::rep;
450    steady_clock::time_point __c_now = steady_clock::now();
451
452#if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
453    using __clock_tp_ns = time_point<steady_clock, nanoseconds>;
454    __ns_rep __now_count_ns = _VSTD::__safe_nanosecond_cast(__c_now.time_since_epoch()).count();
455#else
456    using __clock_tp_ns = time_point<system_clock, nanoseconds>;
457    __ns_rep __now_count_ns = _VSTD::__safe_nanosecond_cast(system_clock::now().time_since_epoch()).count();
458#endif
459
460    __ns_rep __d_ns_count = _VSTD::__safe_nanosecond_cast(__d).count();
461
462    if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) {
463        __do_timed_wait(__lk, __clock_tp_ns::max());
464    } else {
465        __do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count)));
466    }
467
468    return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
469                                                 cv_status::timeout;
470}
471
472template <class _Rep, class _Period, class _Predicate>
473inline
474bool
475condition_variable::wait_for(unique_lock<mutex>& __lk,
476                             const chrono::duration<_Rep, _Period>& __d,
477                             _Predicate __pred)
478{
479    return wait_until(__lk, chrono::steady_clock::now() + __d,
480                      _VSTD::move(__pred));
481}
482
483#if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
484inline
485void
486condition_variable::__do_timed_wait(unique_lock<mutex>& __lk,
487     chrono::time_point<chrono::steady_clock, chrono::nanoseconds> __tp) _NOEXCEPT
488{
489    using namespace chrono;
490    if (!__lk.owns_lock())
491        __throw_system_error(EPERM,
492                            "condition_variable::timed wait: mutex not locked");
493    nanoseconds __d = __tp.time_since_epoch();
494    timespec __ts;
495    seconds __s = duration_cast<seconds>(__d);
496    using __ts_sec = decltype(__ts.tv_sec);
497    const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max();
498    if (__s.count() < __ts_sec_max)
499    {
500        __ts.tv_sec = static_cast<__ts_sec>(__s.count());
501        __ts.tv_nsec = (__d - __s).count();
502    }
503    else
504    {
505        __ts.tv_sec = __ts_sec_max;
506        __ts.tv_nsec = giga::num - 1;
507    }
508    int __ec = pthread_cond_clockwait(&__cv_, __lk.mutex()->native_handle(), CLOCK_MONOTONIC, &__ts);
509    if (__ec != 0 && __ec != ETIMEDOUT)
510        __throw_system_error(__ec, "condition_variable timed_wait failed");
511}
512#endif // _LIBCPP_HAS_COND_CLOCKWAIT
513
514template <class _Clock>
515inline
516void
517condition_variable::__do_timed_wait(unique_lock<mutex>& __lk,
518     chrono::time_point<_Clock, chrono::nanoseconds> __tp) _NOEXCEPT
519{
520    wait_for(__lk, __tp - _Clock::now());
521}
522
523#endif // !_LIBCPP_HAS_NO_THREADS
524
525_LIBCPP_END_NAMESPACE_STD
526
527_LIBCPP_POP_MACROS
528
529#endif // _LIBCPP___MUTEX_BASE
530