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/* _LIBCPP_INLINE_VAR */ constexpr defer_lock_t  defer_lock  = defer_lock_t();
72/* _LIBCPP_INLINE_VAR */ constexpr try_to_lock_t try_to_lock = try_to_lock_t();
73/* _LIBCPP_INLINE_VAR */ 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&) _LIBCPP_EQUAL_DELETE;
100    lock_guard& operator=(lock_guard const&) _LIBCPP_EQUAL_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
143private:
144    unique_lock(unique_lock const&); // = delete;
145    unique_lock& operator=(unique_lock const&); // = delete;
146
147public:
148    _LIBCPP_INLINE_VISIBILITY
149    unique_lock(unique_lock&& __u) _NOEXCEPT
150        : __m_(__u.__m_), __owns_(__u.__owns_)
151        {__u.__m_ = nullptr; __u.__owns_ = false;}
152    _LIBCPP_INLINE_VISIBILITY
153    unique_lock& operator=(unique_lock&& __u) _NOEXCEPT
154        {
155            if (__owns_)
156                __m_->unlock();
157            __m_ = __u.__m_;
158            __owns_ = __u.__owns_;
159            __u.__m_ = nullptr;
160            __u.__owns_ = false;
161            return *this;
162        }
163
164    void lock();
165    bool try_lock();
166
167    template <class _Rep, class _Period>
168        bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
169    template <class _Clock, class _Duration>
170        bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
171
172    void unlock();
173
174    _LIBCPP_INLINE_VISIBILITY
175    void swap(unique_lock& __u) _NOEXCEPT
176    {
177        _VSTD::swap(__m_, __u.__m_);
178        _VSTD::swap(__owns_, __u.__owns_);
179    }
180    _LIBCPP_INLINE_VISIBILITY
181    mutex_type* release() _NOEXCEPT
182    {
183        mutex_type* __m = __m_;
184        __m_ = nullptr;
185        __owns_ = false;
186        return __m;
187    }
188
189    _LIBCPP_INLINE_VISIBILITY
190    bool owns_lock() const _NOEXCEPT {return __owns_;}
191    _LIBCPP_INLINE_VISIBILITY
192    _LIBCPP_EXPLICIT
193        operator bool () const _NOEXCEPT {return __owns_;}
194    _LIBCPP_INLINE_VISIBILITY
195    mutex_type* mutex() const _NOEXCEPT {return __m_;}
196};
197
198template <class _Mutex>
199void
200unique_lock<_Mutex>::lock()
201{
202    if (__m_ == nullptr)
203        __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
204    if (__owns_)
205        __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
206    __m_->lock();
207    __owns_ = true;
208}
209
210template <class _Mutex>
211bool
212unique_lock<_Mutex>::try_lock()
213{
214    if (__m_ == nullptr)
215        __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
216    if (__owns_)
217        __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
218    __owns_ = __m_->try_lock();
219    return __owns_;
220}
221
222template <class _Mutex>
223template <class _Rep, class _Period>
224bool
225unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
226{
227    if (__m_ == nullptr)
228        __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
229    if (__owns_)
230        __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
231    __owns_ = __m_->try_lock_for(__d);
232    return __owns_;
233}
234
235template <class _Mutex>
236template <class _Clock, class _Duration>
237bool
238unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
239{
240    if (__m_ == nullptr)
241        __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
242    if (__owns_)
243        __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
244    __owns_ = __m_->try_lock_until(__t);
245    return __owns_;
246}
247
248template <class _Mutex>
249void
250unique_lock<_Mutex>::unlock()
251{
252    if (!__owns_)
253        __throw_system_error(EPERM, "unique_lock::unlock: not locked");
254    __m_->unlock();
255    __owns_ = false;
256}
257
258template <class _Mutex>
259inline _LIBCPP_INLINE_VISIBILITY
260void
261swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT
262    {__x.swap(__y);}
263
264//enum class cv_status
265_LIBCPP_DECLARE_STRONG_ENUM(cv_status)
266{
267    no_timeout,
268    timeout
269};
270_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status)
271
272class _LIBCPP_TYPE_VIS condition_variable
273{
274    __libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;
275public:
276    _LIBCPP_INLINE_VISIBILITY
277    _LIBCPP_CONSTEXPR condition_variable() _NOEXCEPT = default;
278
279#ifdef _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
280    ~condition_variable() = default;
281#else
282    ~condition_variable();
283#endif
284
285    condition_variable(const condition_variable&) = delete;
286    condition_variable& operator=(const condition_variable&) = delete;
287
288    void notify_one() _NOEXCEPT;
289    void notify_all() _NOEXCEPT;
290
291    void wait(unique_lock<mutex>& __lk) _NOEXCEPT;
292    template <class _Predicate>
293        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
294        void wait(unique_lock<mutex>& __lk, _Predicate __pred);
295
296    template <class _Clock, class _Duration>
297        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
298        cv_status
299        wait_until(unique_lock<mutex>& __lk,
300                   const chrono::time_point<_Clock, _Duration>& __t);
301
302    template <class _Clock, class _Duration, class _Predicate>
303        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
304        bool
305        wait_until(unique_lock<mutex>& __lk,
306                   const chrono::time_point<_Clock, _Duration>& __t,
307                   _Predicate __pred);
308
309    template <class _Rep, class _Period>
310        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
311        cv_status
312        wait_for(unique_lock<mutex>& __lk,
313                 const chrono::duration<_Rep, _Period>& __d);
314
315    template <class _Rep, class _Period, class _Predicate>
316        bool
317        _LIBCPP_INLINE_VISIBILITY
318        wait_for(unique_lock<mutex>& __lk,
319                 const chrono::duration<_Rep, _Period>& __d,
320                 _Predicate __pred);
321
322    typedef __libcpp_condvar_t* native_handle_type;
323    _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
324
325private:
326    void __do_timed_wait(unique_lock<mutex>& __lk,
327       chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;
328#if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
329    void __do_timed_wait(unique_lock<mutex>& __lk,
330       chrono::time_point<chrono::steady_clock, chrono::nanoseconds>) _NOEXCEPT;
331#endif
332    template <class _Clock>
333    void __do_timed_wait(unique_lock<mutex>& __lk,
334       chrono::time_point<_Clock, chrono::nanoseconds>) _NOEXCEPT;
335};
336#endif // !_LIBCPP_HAS_NO_THREADS
337
338template <class _Rep, class _Period>
339inline _LIBCPP_INLINE_VISIBILITY
340typename enable_if
341<
342    is_floating_point<_Rep>::value,
343    chrono::nanoseconds
344>::type
345__safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d)
346{
347    using namespace chrono;
348    using __ratio = ratio_divide<_Period, nano>;
349    using __ns_rep = nanoseconds::rep;
350    _Rep __result_float = __d.count() * __ratio::num / __ratio::den;
351
352    _Rep __result_max = numeric_limits<__ns_rep>::max();
353    if (__result_float >= __result_max) {
354        return nanoseconds::max();
355    }
356
357    _Rep __result_min = numeric_limits<__ns_rep>::min();
358    if (__result_float <= __result_min) {
359        return nanoseconds::min();
360    }
361
362    return nanoseconds(static_cast<__ns_rep>(__result_float));
363}
364
365template <class _Rep, class _Period>
366inline _LIBCPP_INLINE_VISIBILITY
367typename enable_if
368<
369    !is_floating_point<_Rep>::value,
370    chrono::nanoseconds
371>::type
372__safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d)
373{
374    using namespace chrono;
375    if (__d.count() == 0) {
376        return nanoseconds(0);
377    }
378
379    using __ratio = ratio_divide<_Period, nano>;
380    using __ns_rep = nanoseconds::rep;
381    __ns_rep __result_max = numeric_limits<__ns_rep>::max();
382    if (__d.count() > 0 && __d.count() > __result_max / __ratio::num) {
383        return nanoseconds::max();
384    }
385
386    __ns_rep __result_min = numeric_limits<__ns_rep>::min();
387    if (__d.count() < 0 && __d.count() < __result_min / __ratio::num) {
388        return nanoseconds::min();
389    }
390
391    __ns_rep __result = __d.count() * __ratio::num / __ratio::den;
392    if (__result == 0) {
393        return nanoseconds(1);
394    }
395
396    return nanoseconds(__result);
397}
398
399#ifndef _LIBCPP_HAS_NO_THREADS
400template <class _Predicate>
401void
402condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
403{
404    while (!__pred())
405        wait(__lk);
406}
407
408template <class _Clock, class _Duration>
409cv_status
410condition_variable::wait_until(unique_lock<mutex>& __lk,
411                               const chrono::time_point<_Clock, _Duration>& __t)
412{
413    using namespace chrono;
414    using __clock_tp_ns = time_point<_Clock, nanoseconds>;
415
416    typename _Clock::time_point __now = _Clock::now();
417    if (__t <= __now)
418        return cv_status::timeout;
419
420    __clock_tp_ns __t_ns = __clock_tp_ns(_VSTD::__safe_nanosecond_cast(__t.time_since_epoch()));
421
422    __do_timed_wait(__lk, __t_ns);
423    return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
424}
425
426template <class _Clock, class _Duration, class _Predicate>
427bool
428condition_variable::wait_until(unique_lock<mutex>& __lk,
429                   const chrono::time_point<_Clock, _Duration>& __t,
430                   _Predicate __pred)
431{
432    while (!__pred())
433    {
434        if (wait_until(__lk, __t) == cv_status::timeout)
435            return __pred();
436    }
437    return true;
438}
439
440template <class _Rep, class _Period>
441cv_status
442condition_variable::wait_for(unique_lock<mutex>& __lk,
443                             const chrono::duration<_Rep, _Period>& __d)
444{
445    using namespace chrono;
446    if (__d <= __d.zero())
447        return cv_status::timeout;
448    using __ns_rep = nanoseconds::rep;
449    steady_clock::time_point __c_now = steady_clock::now();
450
451#if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
452    using __clock_tp_ns = time_point<steady_clock, nanoseconds>;
453    __ns_rep __now_count_ns = _VSTD::__safe_nanosecond_cast(__c_now.time_since_epoch()).count();
454#else
455    using __clock_tp_ns = time_point<system_clock, nanoseconds>;
456    __ns_rep __now_count_ns = _VSTD::__safe_nanosecond_cast(system_clock::now().time_since_epoch()).count();
457#endif
458
459    __ns_rep __d_ns_count = _VSTD::__safe_nanosecond_cast(__d).count();
460
461    if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) {
462        __do_timed_wait(__lk, __clock_tp_ns::max());
463    } else {
464        __do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count)));
465    }
466
467    return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
468                                                 cv_status::timeout;
469}
470
471template <class _Rep, class _Period, class _Predicate>
472inline
473bool
474condition_variable::wait_for(unique_lock<mutex>& __lk,
475                             const chrono::duration<_Rep, _Period>& __d,
476                             _Predicate __pred)
477{
478    return wait_until(__lk, chrono::steady_clock::now() + __d,
479                      _VSTD::move(__pred));
480}
481
482#if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
483inline
484void
485condition_variable::__do_timed_wait(unique_lock<mutex>& __lk,
486     chrono::time_point<chrono::steady_clock, chrono::nanoseconds> __tp) _NOEXCEPT
487{
488    using namespace chrono;
489    if (!__lk.owns_lock())
490        __throw_system_error(EPERM,
491                            "condition_variable::timed wait: mutex not locked");
492    nanoseconds __d = __tp.time_since_epoch();
493    timespec __ts;
494    seconds __s = duration_cast<seconds>(__d);
495    using __ts_sec = decltype(__ts.tv_sec);
496    const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max();
497    if (__s.count() < __ts_sec_max)
498    {
499        __ts.tv_sec = static_cast<__ts_sec>(__s.count());
500        __ts.tv_nsec = (__d - __s).count();
501    }
502    else
503    {
504        __ts.tv_sec = __ts_sec_max;
505        __ts.tv_nsec = giga::num - 1;
506    }
507    int __ec = pthread_cond_clockwait(&__cv_, __lk.mutex()->native_handle(), CLOCK_MONOTONIC, &__ts);
508    if (__ec != 0 && __ec != ETIMEDOUT)
509        __throw_system_error(__ec, "condition_variable timed_wait failed");
510}
511#endif // _LIBCPP_HAS_COND_CLOCKWAIT
512
513template <class _Clock>
514inline
515void
516condition_variable::__do_timed_wait(unique_lock<mutex>& __lk,
517     chrono::time_point<_Clock, chrono::nanoseconds> __tp) _NOEXCEPT
518{
519    wait_for(__lk, __tp - _Clock::now());
520}
521
522#endif // !_LIBCPP_HAS_NO_THREADS
523
524_LIBCPP_END_NAMESPACE_STD
525
526_LIBCPP_POP_MACROS
527
528#endif // _LIBCPP___MUTEX_BASE
529