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 <__chrono/duration.h>
14#include <__chrono/steady_clock.h>
15#include <__chrono/system_clock.h>
16#include <__chrono/time_point.h>
17#include <__config>
18#include <__threading_support>
19#include <ratio>
20#include <system_error>
21#include <time.h>
22
23#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
24#  pragma GCC system_header
25#endif
26
27_LIBCPP_PUSH_MACROS
28#include <__undef_macros>
29
30
31_LIBCPP_BEGIN_NAMESPACE_STD
32
33#ifndef _LIBCPP_HAS_NO_THREADS
34
35class _LIBCPP_TYPE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mutex
36{
37    __libcpp_mutex_t __m_ = _LIBCPP_MUTEX_INITIALIZER;
38
39public:
40    _LIBCPP_INLINE_VISIBILITY
41    _LIBCPP_CONSTEXPR mutex() = default;
42
43    mutex(const mutex&) = delete;
44    mutex& operator=(const mutex&) = delete;
45
46#if defined(_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION)
47    ~mutex() = default;
48#else
49    ~mutex() _NOEXCEPT;
50#endif
51
52    void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability());
53    bool try_lock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
54    void unlock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
55
56    typedef __libcpp_mutex_t* native_handle_type;
57    _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
58};
59
60static_assert(is_nothrow_default_constructible<mutex>::value,
61              "the default constructor for std::mutex must be nothrow");
62
63struct _LIBCPP_TYPE_VIS defer_lock_t { explicit defer_lock_t() = default; };
64struct _LIBCPP_TYPE_VIS try_to_lock_t { explicit try_to_lock_t() = default; };
65struct _LIBCPP_TYPE_VIS adopt_lock_t { explicit adopt_lock_t() = default; };
66
67#if defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY)
68
69extern _LIBCPP_EXPORTED_FROM_ABI const defer_lock_t  defer_lock;
70extern _LIBCPP_EXPORTED_FROM_ABI const try_to_lock_t try_to_lock;
71extern _LIBCPP_EXPORTED_FROM_ABI const adopt_lock_t  adopt_lock;
72
73#else
74
75/* inline */ constexpr defer_lock_t  defer_lock  = defer_lock_t();
76/* inline */ constexpr try_to_lock_t try_to_lock = try_to_lock_t();
77/* inline */ constexpr adopt_lock_t  adopt_lock  = adopt_lock_t();
78
79#endif
80
81template <class _Mutex>
82class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable)
83lock_guard
84{
85public:
86    typedef _Mutex mutex_type;
87
88private:
89    mutex_type& __m_;
90public:
91
92    _LIBCPP_NODISCARD_EXT _LIBCPP_INLINE_VISIBILITY
93    explicit lock_guard(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m))
94        : __m_(__m) {__m_.lock();}
95
96    _LIBCPP_NODISCARD_EXT _LIBCPP_INLINE_VISIBILITY
97    lock_guard(mutex_type& __m, adopt_lock_t) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
98        : __m_(__m) {}
99    _LIBCPP_INLINE_VISIBILITY
100    ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();}
101
102private:
103    lock_guard(lock_guard const&) = delete;
104    lock_guard& operator=(lock_guard const&) = delete;
105};
106
107template <class _Mutex>
108class _LIBCPP_TEMPLATE_VIS unique_lock
109{
110public:
111    typedef _Mutex mutex_type;
112
113private:
114    mutex_type* __m_;
115    bool __owns_;
116
117public:
118    _LIBCPP_INLINE_VISIBILITY
119    unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
120    _LIBCPP_INLINE_VISIBILITY
121    explicit unique_lock(mutex_type& __m)
122        : __m_(_VSTD::addressof(__m)), __owns_(true) {__m_->lock();}
123    _LIBCPP_INLINE_VISIBILITY
124    unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
125        : __m_(_VSTD::addressof(__m)), __owns_(false) {}
126    _LIBCPP_INLINE_VISIBILITY
127    unique_lock(mutex_type& __m, try_to_lock_t)
128        : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock()) {}
129    _LIBCPP_INLINE_VISIBILITY
130    unique_lock(mutex_type& __m, adopt_lock_t)
131        : __m_(_VSTD::addressof(__m)), __owns_(true) {}
132    template <class _Clock, class _Duration>
133    _LIBCPP_INLINE_VISIBILITY
134        unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t)
135            : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_until(__t)) {}
136    template <class _Rep, class _Period>
137    _LIBCPP_INLINE_VISIBILITY
138        unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
139            : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_for(__d)) {}
140    _LIBCPP_INLINE_VISIBILITY
141    ~unique_lock()
142    {
143        if (__owns_)
144            __m_->unlock();
145    }
146
147    unique_lock(unique_lock const&) = delete;
148    unique_lock& operator=(unique_lock const&) = delete;
149
150    _LIBCPP_INLINE_VISIBILITY
151    unique_lock(unique_lock&& __u) _NOEXCEPT
152        : __m_(__u.__m_), __owns_(__u.__owns_)
153        {__u.__m_ = nullptr; __u.__owns_ = false;}
154    _LIBCPP_INLINE_VISIBILITY
155    unique_lock& operator=(unique_lock&& __u) _NOEXCEPT
156        {
157            if (__owns_)
158                __m_->unlock();
159            __m_ = __u.__m_;
160            __owns_ = __u.__owns_;
161            __u.__m_ = nullptr;
162            __u.__owns_ = false;
163            return *this;
164        }
165
166    void lock();
167    bool try_lock();
168
169    template <class _Rep, class _Period>
170        bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
171    template <class _Clock, class _Duration>
172        bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
173
174    void unlock();
175
176    _LIBCPP_INLINE_VISIBILITY
177    void swap(unique_lock& __u) _NOEXCEPT
178    {
179        _VSTD::swap(__m_, __u.__m_);
180        _VSTD::swap(__owns_, __u.__owns_);
181    }
182    _LIBCPP_INLINE_VISIBILITY
183    mutex_type* release() _NOEXCEPT
184    {
185        mutex_type* __m = __m_;
186        __m_ = nullptr;
187        __owns_ = false;
188        return __m;
189    }
190
191    _LIBCPP_INLINE_VISIBILITY
192    bool owns_lock() const _NOEXCEPT {return __owns_;}
193    _LIBCPP_INLINE_VISIBILITY
194    explicit 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
341__enable_if_t<is_floating_point<_Rep>::value, chrono::nanoseconds>
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
364__enable_if_t<!is_floating_point<_Rep>::value, chrono::nanoseconds>
365__safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d)
366{
367    using namespace chrono;
368    if (__d.count() == 0) {
369        return nanoseconds(0);
370    }
371
372    using __ratio = ratio_divide<_Period, nano>;
373    using __ns_rep = nanoseconds::rep;
374    __ns_rep __result_max = numeric_limits<__ns_rep>::max();
375    if (__d.count() > 0 && __d.count() > __result_max / __ratio::num) {
376        return nanoseconds::max();
377    }
378
379    __ns_rep __result_min = numeric_limits<__ns_rep>::min();
380    if (__d.count() < 0 && __d.count() < __result_min / __ratio::num) {
381        return nanoseconds::min();
382    }
383
384    __ns_rep __result = __d.count() * __ratio::num / __ratio::den;
385    if (__result == 0) {
386        return nanoseconds(1);
387    }
388
389    return nanoseconds(__result);
390}
391
392#ifndef _LIBCPP_HAS_NO_THREADS
393template <class _Predicate>
394void
395condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
396{
397    while (!__pred())
398        wait(__lk);
399}
400
401template <class _Clock, class _Duration>
402cv_status
403condition_variable::wait_until(unique_lock<mutex>& __lk,
404                               const chrono::time_point<_Clock, _Duration>& __t)
405{
406    using namespace chrono;
407    using __clock_tp_ns = time_point<_Clock, nanoseconds>;
408
409    typename _Clock::time_point __now = _Clock::now();
410    if (__t <= __now)
411        return cv_status::timeout;
412
413    __clock_tp_ns __t_ns = __clock_tp_ns(_VSTD::__safe_nanosecond_cast(__t.time_since_epoch()));
414
415    __do_timed_wait(__lk, __t_ns);
416    return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
417}
418
419template <class _Clock, class _Duration, class _Predicate>
420bool
421condition_variable::wait_until(unique_lock<mutex>& __lk,
422                   const chrono::time_point<_Clock, _Duration>& __t,
423                   _Predicate __pred)
424{
425    while (!__pred())
426    {
427        if (wait_until(__lk, __t) == cv_status::timeout)
428            return __pred();
429    }
430    return true;
431}
432
433template <class _Rep, class _Period>
434cv_status
435condition_variable::wait_for(unique_lock<mutex>& __lk,
436                             const chrono::duration<_Rep, _Period>& __d)
437{
438    using namespace chrono;
439    if (__d <= __d.zero())
440        return cv_status::timeout;
441    using __ns_rep = nanoseconds::rep;
442    steady_clock::time_point __c_now = steady_clock::now();
443
444#if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
445    using __clock_tp_ns = time_point<steady_clock, nanoseconds>;
446    __ns_rep __now_count_ns = _VSTD::__safe_nanosecond_cast(__c_now.time_since_epoch()).count();
447#else
448    using __clock_tp_ns = time_point<system_clock, nanoseconds>;
449    __ns_rep __now_count_ns = _VSTD::__safe_nanosecond_cast(system_clock::now().time_since_epoch()).count();
450#endif
451
452    __ns_rep __d_ns_count = _VSTD::__safe_nanosecond_cast(__d).count();
453
454    if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) {
455        __do_timed_wait(__lk, __clock_tp_ns::max());
456    } else {
457        __do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count)));
458    }
459
460    return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
461                                                 cv_status::timeout;
462}
463
464template <class _Rep, class _Period, class _Predicate>
465inline
466bool
467condition_variable::wait_for(unique_lock<mutex>& __lk,
468                             const chrono::duration<_Rep, _Period>& __d,
469                             _Predicate __pred)
470{
471    return wait_until(__lk, chrono::steady_clock::now() + __d,
472                      _VSTD::move(__pred));
473}
474
475#if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
476inline
477void
478condition_variable::__do_timed_wait(unique_lock<mutex>& __lk,
479     chrono::time_point<chrono::steady_clock, chrono::nanoseconds> __tp) _NOEXCEPT
480{
481    using namespace chrono;
482    if (!__lk.owns_lock())
483        __throw_system_error(EPERM,
484                            "condition_variable::timed wait: mutex not locked");
485    nanoseconds __d = __tp.time_since_epoch();
486    timespec __ts;
487    seconds __s = duration_cast<seconds>(__d);
488    using __ts_sec = decltype(__ts.tv_sec);
489    const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max();
490    if (__s.count() < __ts_sec_max)
491    {
492        __ts.tv_sec = static_cast<__ts_sec>(__s.count());
493        __ts.tv_nsec = (__d - __s).count();
494    }
495    else
496    {
497        __ts.tv_sec = __ts_sec_max;
498        __ts.tv_nsec = giga::num - 1;
499    }
500    int __ec = pthread_cond_clockwait(&__cv_, __lk.mutex()->native_handle(), CLOCK_MONOTONIC, &__ts);
501    if (__ec != 0 && __ec != ETIMEDOUT)
502        __throw_system_error(__ec, "condition_variable timed_wait failed");
503}
504#endif // _LIBCPP_HAS_COND_CLOCKWAIT
505
506template <class _Clock>
507inline
508void
509condition_variable::__do_timed_wait(unique_lock<mutex>& __lk,
510     chrono::time_point<_Clock, chrono::nanoseconds> __tp) _NOEXCEPT
511{
512    wait_for(__lk, __tp - _Clock::now());
513}
514
515#endif // !_LIBCPP_HAS_NO_THREADS
516
517_LIBCPP_END_NAMESPACE_STD
518
519_LIBCPP_POP_MACROS
520
521#endif // _LIBCPP___MUTEX_BASE
522