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