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