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 <chrono>
15#include <system_error>
16#include <__threading_support>
17
18#include <time.h>
19
20#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
21#pragma GCC system_header
22#endif
23
24_LIBCPP_PUSH_MACROS
25#include <__undef_macros>
26
27
28_LIBCPP_BEGIN_NAMESPACE_STD
29
30#ifndef _LIBCPP_HAS_NO_THREADS
31
32class _LIBCPP_TYPE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mutex
33{
34    __libcpp_mutex_t __m_ = _LIBCPP_MUTEX_INITIALIZER;
35
36public:
37    _LIBCPP_INLINE_VISIBILITY
38    _LIBCPP_CONSTEXPR mutex() = default;
39
40    mutex(const mutex&) = delete;
41    mutex& operator=(const mutex&) = delete;
42
43#if defined(_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION)
44    ~mutex() = default;
45#else
46    ~mutex() _NOEXCEPT;
47#endif
48
49    void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability());
50    bool try_lock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
51    void unlock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
52
53    typedef __libcpp_mutex_t* native_handle_type;
54    _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
55};
56
57static_assert(is_nothrow_default_constructible<mutex>::value,
58              "the default constructor for std::mutex must be nothrow");
59
60struct _LIBCPP_TYPE_VIS defer_lock_t { explicit defer_lock_t() = default; };
61struct _LIBCPP_TYPE_VIS try_to_lock_t { explicit try_to_lock_t() = default; };
62struct _LIBCPP_TYPE_VIS adopt_lock_t { explicit adopt_lock_t() = default; };
63
64#if defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY)
65
66extern _LIBCPP_EXPORTED_FROM_ABI const defer_lock_t  defer_lock;
67extern _LIBCPP_EXPORTED_FROM_ABI const try_to_lock_t try_to_lock;
68extern _LIBCPP_EXPORTED_FROM_ABI const adopt_lock_t  adopt_lock;
69
70#else
71
72/* _LIBCPP_INLINE_VAR */ constexpr defer_lock_t  defer_lock  = defer_lock_t();
73/* _LIBCPP_INLINE_VAR */ constexpr try_to_lock_t try_to_lock = try_to_lock_t();
74/* _LIBCPP_INLINE_VAR */ constexpr adopt_lock_t  adopt_lock  = adopt_lock_t();
75
76#endif
77
78template <class _Mutex>
79class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable)
80lock_guard
81{
82public:
83    typedef _Mutex mutex_type;
84
85private:
86    mutex_type& __m_;
87public:
88
89    _LIBCPP_NODISCARD_EXT _LIBCPP_INLINE_VISIBILITY
90    explicit lock_guard(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m))
91        : __m_(__m) {__m_.lock();}
92
93    _LIBCPP_NODISCARD_EXT _LIBCPP_INLINE_VISIBILITY
94    lock_guard(mutex_type& __m, adopt_lock_t) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
95        : __m_(__m) {}
96    _LIBCPP_INLINE_VISIBILITY
97    ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();}
98
99private:
100    lock_guard(lock_guard const&) _LIBCPP_EQUAL_DELETE;
101    lock_guard& operator=(lock_guard const&) _LIBCPP_EQUAL_DELETE;
102};
103
104template <class _Mutex>
105class _LIBCPP_TEMPLATE_VIS unique_lock
106{
107public:
108    typedef _Mutex mutex_type;
109
110private:
111    mutex_type* __m_;
112    bool __owns_;
113
114public:
115    _LIBCPP_INLINE_VISIBILITY
116    unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
117    _LIBCPP_INLINE_VISIBILITY
118    explicit unique_lock(mutex_type& __m)
119        : __m_(_VSTD::addressof(__m)), __owns_(true) {__m_->lock();}
120    _LIBCPP_INLINE_VISIBILITY
121    unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
122        : __m_(_VSTD::addressof(__m)), __owns_(false) {}
123    _LIBCPP_INLINE_VISIBILITY
124    unique_lock(mutex_type& __m, try_to_lock_t)
125        : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock()) {}
126    _LIBCPP_INLINE_VISIBILITY
127    unique_lock(mutex_type& __m, adopt_lock_t)
128        : __m_(_VSTD::addressof(__m)), __owns_(true) {}
129    template <class _Clock, class _Duration>
130    _LIBCPP_INLINE_VISIBILITY
131        unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t)
132            : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_until(__t)) {}
133    template <class _Rep, class _Period>
134    _LIBCPP_INLINE_VISIBILITY
135        unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
136            : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_for(__d)) {}
137    _LIBCPP_INLINE_VISIBILITY
138    ~unique_lock()
139    {
140        if (__owns_)
141            __m_->unlock();
142    }
143
144private:
145    unique_lock(unique_lock const&); // = delete;
146    unique_lock& operator=(unique_lock const&); // = delete;
147
148public:
149    _LIBCPP_INLINE_VISIBILITY
150    unique_lock(unique_lock&& __u) _NOEXCEPT
151        : __m_(__u.__m_), __owns_(__u.__owns_)
152        {__u.__m_ = nullptr; __u.__owns_ = false;}
153    _LIBCPP_INLINE_VISIBILITY
154    unique_lock& operator=(unique_lock&& __u) _NOEXCEPT
155        {
156            if (__owns_)
157                __m_->unlock();
158            __m_ = __u.__m_;
159            __owns_ = __u.__owns_;
160            __u.__m_ = nullptr;
161            __u.__owns_ = false;
162            return *this;
163        }
164
165    void lock();
166    bool try_lock();
167
168    template <class _Rep, class _Period>
169        bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
170    template <class _Clock, class _Duration>
171        bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
172
173    void unlock();
174
175    _LIBCPP_INLINE_VISIBILITY
176    void swap(unique_lock& __u) _NOEXCEPT
177    {
178        _VSTD::swap(__m_, __u.__m_);
179        _VSTD::swap(__owns_, __u.__owns_);
180    }
181    _LIBCPP_INLINE_VISIBILITY
182    mutex_type* release() _NOEXCEPT
183    {
184        mutex_type* __m = __m_;
185        __m_ = nullptr;
186        __owns_ = false;
187        return __m;
188    }
189
190    _LIBCPP_INLINE_VISIBILITY
191    bool owns_lock() const _NOEXCEPT {return __owns_;}
192    _LIBCPP_INLINE_VISIBILITY
193    _LIBCPP_EXPLICIT
194        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(__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 = __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 = __safe_nanosecond_cast(system_clock::now().time_since_epoch()).count();
458#endif
459
460    __ns_rep __d_ns_count = __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