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