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