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
19#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
20#pragma GCC system_header
21#endif
22
23_LIBCPP_PUSH_MACROS
24#include <__undef_macros>
25
26
27_LIBCPP_BEGIN_NAMESPACE_STD
28
29#ifndef _LIBCPP_HAS_NO_THREADS
30
31#ifndef _LIBCPP_THREAD_SAFETY_ANNOTATION
32#  ifdef _LIBCPP_HAS_THREAD_SAFETY_ANNOTATIONS
33#    define _LIBCPP_THREAD_SAFETY_ANNOTATION(x) __attribute__((x))
34#  else
35#    define _LIBCPP_THREAD_SAFETY_ANNOTATION(x)
36#  endif
37#endif  // _LIBCPP_THREAD_SAFETY_ANNOTATION
38
39class _LIBCPP_TYPE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mutex
40{
41#ifndef _LIBCPP_CXX03_LANG
42    __libcpp_mutex_t __m_ = _LIBCPP_MUTEX_INITIALIZER;
43#else
44    __libcpp_mutex_t __m_;
45#endif
46
47public:
48    _LIBCPP_INLINE_VISIBILITY
49#ifndef _LIBCPP_CXX03_LANG
50    constexpr mutex() = default;
51#else
52    mutex() _NOEXCEPT {__m_ = (__libcpp_mutex_t)_LIBCPP_MUTEX_INITIALIZER;}
53#endif
54    ~mutex();
55
56private:
57    mutex(const mutex&);// = delete;
58    mutex& operator=(const mutex&);// = delete;
59
60public:
61    void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability());
62    bool try_lock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
63    void unlock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
64
65    typedef __libcpp_mutex_t* native_handle_type;
66    _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
67};
68
69static_assert(is_nothrow_default_constructible<mutex>::value,
70              "the default constructor for std::mutex must be nothrow");
71
72struct _LIBCPP_TYPE_VIS defer_lock_t {};
73struct _LIBCPP_TYPE_VIS try_to_lock_t {};
74struct _LIBCPP_TYPE_VIS adopt_lock_t {};
75
76#if defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY)
77
78extern _LIBCPP_EXPORTED_FROM_ABI const defer_lock_t  defer_lock;
79extern _LIBCPP_EXPORTED_FROM_ABI const try_to_lock_t try_to_lock;
80extern _LIBCPP_EXPORTED_FROM_ABI const adopt_lock_t  adopt_lock;
81
82#else
83
84/* _LIBCPP_INLINE_VAR */ constexpr defer_lock_t  defer_lock  = defer_lock_t();
85/* _LIBCPP_INLINE_VAR */ constexpr try_to_lock_t try_to_lock = try_to_lock_t();
86/* _LIBCPP_INLINE_VAR */ constexpr adopt_lock_t  adopt_lock  = adopt_lock_t();
87
88#endif
89
90template <class _Mutex>
91class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable)
92lock_guard
93{
94public:
95    typedef _Mutex mutex_type;
96
97private:
98    mutex_type& __m_;
99public:
100
101    _LIBCPP_INLINE_VISIBILITY
102    explicit lock_guard(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m))
103        : __m_(__m) {__m_.lock();}
104    _LIBCPP_INLINE_VISIBILITY
105    lock_guard(mutex_type& __m, adopt_lock_t) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
106        : __m_(__m) {}
107    _LIBCPP_INLINE_VISIBILITY
108    ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();}
109
110private:
111    lock_guard(lock_guard const&) _LIBCPP_EQUAL_DELETE;
112    lock_guard& operator=(lock_guard const&) _LIBCPP_EQUAL_DELETE;
113};
114
115template <class _Mutex>
116class _LIBCPP_TEMPLATE_VIS unique_lock
117{
118public:
119    typedef _Mutex mutex_type;
120
121private:
122    mutex_type* __m_;
123    bool __owns_;
124
125public:
126    _LIBCPP_INLINE_VISIBILITY
127    unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
128    _LIBCPP_INLINE_VISIBILITY
129    explicit unique_lock(mutex_type& __m)
130        : __m_(_VSTD::addressof(__m)), __owns_(true) {__m_->lock();}
131    _LIBCPP_INLINE_VISIBILITY
132    unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
133        : __m_(_VSTD::addressof(__m)), __owns_(false) {}
134    _LIBCPP_INLINE_VISIBILITY
135    unique_lock(mutex_type& __m, try_to_lock_t)
136        : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock()) {}
137    _LIBCPP_INLINE_VISIBILITY
138    unique_lock(mutex_type& __m, adopt_lock_t)
139        : __m_(_VSTD::addressof(__m)), __owns_(true) {}
140    template <class _Clock, class _Duration>
141    _LIBCPP_INLINE_VISIBILITY
142        unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t)
143            : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_until(__t)) {}
144    template <class _Rep, class _Period>
145    _LIBCPP_INLINE_VISIBILITY
146        unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
147            : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_for(__d)) {}
148    _LIBCPP_INLINE_VISIBILITY
149    ~unique_lock()
150    {
151        if (__owns_)
152            __m_->unlock();
153    }
154
155private:
156    unique_lock(unique_lock const&); // = delete;
157    unique_lock& operator=(unique_lock const&); // = delete;
158
159public:
160#ifndef _LIBCPP_CXX03_LANG
161    _LIBCPP_INLINE_VISIBILITY
162    unique_lock(unique_lock&& __u) _NOEXCEPT
163        : __m_(__u.__m_), __owns_(__u.__owns_)
164        {__u.__m_ = nullptr; __u.__owns_ = false;}
165    _LIBCPP_INLINE_VISIBILITY
166    unique_lock& operator=(unique_lock&& __u) _NOEXCEPT
167        {
168            if (__owns_)
169                __m_->unlock();
170            __m_ = __u.__m_;
171            __owns_ = __u.__owns_;
172            __u.__m_ = nullptr;
173            __u.__owns_ = false;
174            return *this;
175        }
176
177#endif  // _LIBCPP_CXX03_LANG
178
179    void lock();
180    bool try_lock();
181
182    template <class _Rep, class _Period>
183        bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
184    template <class _Clock, class _Duration>
185        bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
186
187    void unlock();
188
189    _LIBCPP_INLINE_VISIBILITY
190    void swap(unique_lock& __u) _NOEXCEPT
191    {
192        _VSTD::swap(__m_, __u.__m_);
193        _VSTD::swap(__owns_, __u.__owns_);
194    }
195    _LIBCPP_INLINE_VISIBILITY
196    mutex_type* release() _NOEXCEPT
197    {
198        mutex_type* __m = __m_;
199        __m_ = nullptr;
200        __owns_ = false;
201        return __m;
202    }
203
204    _LIBCPP_INLINE_VISIBILITY
205    bool owns_lock() const _NOEXCEPT {return __owns_;}
206    _LIBCPP_INLINE_VISIBILITY
207    _LIBCPP_EXPLICIT
208        operator bool () const _NOEXCEPT {return __owns_;}
209    _LIBCPP_INLINE_VISIBILITY
210    mutex_type* mutex() const _NOEXCEPT {return __m_;}
211};
212
213template <class _Mutex>
214void
215unique_lock<_Mutex>::lock()
216{
217    if (__m_ == nullptr)
218        __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
219    if (__owns_)
220        __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
221    __m_->lock();
222    __owns_ = true;
223}
224
225template <class _Mutex>
226bool
227unique_lock<_Mutex>::try_lock()
228{
229    if (__m_ == nullptr)
230        __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
231    if (__owns_)
232        __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
233    __owns_ = __m_->try_lock();
234    return __owns_;
235}
236
237template <class _Mutex>
238template <class _Rep, class _Period>
239bool
240unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
241{
242    if (__m_ == nullptr)
243        __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
244    if (__owns_)
245        __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
246    __owns_ = __m_->try_lock_for(__d);
247    return __owns_;
248}
249
250template <class _Mutex>
251template <class _Clock, class _Duration>
252bool
253unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
254{
255    if (__m_ == nullptr)
256        __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
257    if (__owns_)
258        __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
259    __owns_ = __m_->try_lock_until(__t);
260    return __owns_;
261}
262
263template <class _Mutex>
264void
265unique_lock<_Mutex>::unlock()
266{
267    if (!__owns_)
268        __throw_system_error(EPERM, "unique_lock::unlock: not locked");
269    __m_->unlock();
270    __owns_ = false;
271}
272
273template <class _Mutex>
274inline _LIBCPP_INLINE_VISIBILITY
275void
276swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT
277    {__x.swap(__y);}
278
279//enum class cv_status
280_LIBCPP_DECLARE_STRONG_ENUM(cv_status)
281{
282    no_timeout,
283    timeout
284};
285_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status)
286
287class _LIBCPP_TYPE_VIS condition_variable
288{
289#ifndef _LIBCPP_CXX03_LANG
290    __libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;
291#else
292    __libcpp_condvar_t __cv_;
293#endif
294
295public:
296    _LIBCPP_INLINE_VISIBILITY
297#ifndef _LIBCPP_CXX03_LANG
298    constexpr condition_variable() _NOEXCEPT = default;
299#else
300    condition_variable() _NOEXCEPT {__cv_ = (__libcpp_condvar_t)_LIBCPP_CONDVAR_INITIALIZER;}
301#endif
302    ~condition_variable();
303
304private:
305    condition_variable(const condition_variable&); // = delete;
306    condition_variable& operator=(const condition_variable&); // = delete;
307
308public:
309    void notify_one() _NOEXCEPT;
310    void notify_all() _NOEXCEPT;
311
312    void wait(unique_lock<mutex>& __lk) _NOEXCEPT;
313    template <class _Predicate>
314        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
315        void wait(unique_lock<mutex>& __lk, _Predicate __pred);
316
317    template <class _Clock, class _Duration>
318        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
319        cv_status
320        wait_until(unique_lock<mutex>& __lk,
321                   const chrono::time_point<_Clock, _Duration>& __t);
322
323    template <class _Clock, class _Duration, class _Predicate>
324        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
325        bool
326        wait_until(unique_lock<mutex>& __lk,
327                   const chrono::time_point<_Clock, _Duration>& __t,
328                   _Predicate __pred);
329
330    template <class _Rep, class _Period>
331        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
332        cv_status
333        wait_for(unique_lock<mutex>& __lk,
334                 const chrono::duration<_Rep, _Period>& __d);
335
336    template <class _Rep, class _Period, class _Predicate>
337        bool
338        _LIBCPP_INLINE_VISIBILITY
339        wait_for(unique_lock<mutex>& __lk,
340                 const chrono::duration<_Rep, _Period>& __d,
341                 _Predicate __pred);
342
343    typedef __libcpp_condvar_t* native_handle_type;
344    _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
345
346private:
347    void __do_timed_wait(unique_lock<mutex>& __lk,
348       chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;
349};
350#endif // !_LIBCPP_HAS_NO_THREADS
351
352template <class _To, class _Rep, class _Period>
353inline _LIBCPP_INLINE_VISIBILITY
354typename enable_if
355<
356    chrono::__is_duration<_To>::value,
357    _To
358>::type
359__ceil(chrono::duration<_Rep, _Period> __d)
360{
361    using namespace chrono;
362    _To __r = duration_cast<_To>(__d);
363    if (__r < __d)
364        ++__r;
365    return __r;
366}
367
368#ifndef _LIBCPP_HAS_NO_THREADS
369template <class _Predicate>
370void
371condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
372{
373    while (!__pred())
374        wait(__lk);
375}
376
377template <class _Clock, class _Duration>
378cv_status
379condition_variable::wait_until(unique_lock<mutex>& __lk,
380                               const chrono::time_point<_Clock, _Duration>& __t)
381{
382    using namespace chrono;
383    wait_for(__lk, __t - _Clock::now());
384    return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
385}
386
387template <class _Clock, class _Duration, class _Predicate>
388bool
389condition_variable::wait_until(unique_lock<mutex>& __lk,
390                   const chrono::time_point<_Clock, _Duration>& __t,
391                   _Predicate __pred)
392{
393    while (!__pred())
394    {
395        if (wait_until(__lk, __t) == cv_status::timeout)
396            return __pred();
397    }
398    return true;
399}
400
401template <class _Rep, class _Period>
402cv_status
403condition_variable::wait_for(unique_lock<mutex>& __lk,
404                             const chrono::duration<_Rep, _Period>& __d)
405{
406    using namespace chrono;
407    if (__d <= __d.zero())
408        return cv_status::timeout;
409    typedef time_point<system_clock, duration<long double, nano> > __sys_tpf;
410    typedef time_point<system_clock, nanoseconds> __sys_tpi;
411    __sys_tpf _Max = __sys_tpi::max();
412    steady_clock::time_point __c_now = steady_clock::now();
413    system_clock::time_point __s_now = system_clock::now();
414    if (_Max - __d > __s_now)
415        __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d));
416    else
417        __do_timed_wait(__lk, __sys_tpi::max());
418    return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
419                                                 cv_status::timeout;
420}
421
422template <class _Rep, class _Period, class _Predicate>
423inline
424bool
425condition_variable::wait_for(unique_lock<mutex>& __lk,
426                             const chrono::duration<_Rep, _Period>& __d,
427                             _Predicate __pred)
428{
429    return wait_until(__lk, chrono::steady_clock::now() + __d,
430                      _VSTD::move(__pred));
431}
432
433#endif // !_LIBCPP_HAS_NO_THREADS
434
435_LIBCPP_END_NAMESPACE_STD
436
437_LIBCPP_POP_MACROS
438
439#endif  // _LIBCPP___MUTEX_BASE
440