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