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