1227825Stheraven// -*- C++ -*-
2227825Stheraven//===----------------------------------------------------------------------===//
3227825Stheraven//
4227825Stheraven//                     The LLVM Compiler Infrastructure
5227825Stheraven//
6227825Stheraven// This file is dual licensed under the MIT and the University of Illinois Open
7227825Stheraven// Source Licenses. See LICENSE.TXT for details.
8227825Stheraven//
9227825Stheraven//===----------------------------------------------------------------------===//
10227825Stheraven
11227825Stheraven#ifndef _LIBCPP___MUTEX_BASE
12227825Stheraven#define _LIBCPP___MUTEX_BASE
13227825Stheraven
14227825Stheraven#include <__config>
15227825Stheraven#include <chrono>
16227825Stheraven#include <system_error>
17227825Stheraven#include <pthread.h>
18227825Stheraven
19227825Stheraven#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
20227825Stheraven#pragma GCC system_header
21227825Stheraven#endif
22227825Stheraven
23227825Stheraven_LIBCPP_BEGIN_NAMESPACE_STD
24227825Stheraven
25278724Sdim#ifndef _LIBCPP_HAS_NO_THREADS
26278724Sdim
27249998Sdimclass _LIBCPP_TYPE_VIS mutex
28227825Stheraven{
29227825Stheraven    pthread_mutex_t __m_;
30227825Stheraven
31227825Stheravenpublic:
32227825Stheraven    _LIBCPP_INLINE_VISIBILITY
33241903Sdim#ifndef _LIBCPP_HAS_NO_CONSTEXPR
34241903Sdim     constexpr mutex() _NOEXCEPT : __m_(PTHREAD_MUTEX_INITIALIZER) {}
35241903Sdim#else
36241903Sdim     mutex() _NOEXCEPT {__m_ = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;}
37241903Sdim#endif
38227825Stheraven     ~mutex();
39227825Stheraven
40227825Stheravenprivate:
41227825Stheraven    mutex(const mutex&);// = delete;
42227825Stheraven    mutex& operator=(const mutex&);// = delete;
43227825Stheraven
44227825Stheravenpublic:
45227825Stheraven    void lock();
46241903Sdim    bool try_lock() _NOEXCEPT;
47241903Sdim    void unlock() _NOEXCEPT;
48227825Stheraven
49227825Stheraven    typedef pthread_mutex_t* native_handle_type;
50227825Stheraven    _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
51227825Stheraven};
52227825Stheraven
53249998Sdimstruct _LIBCPP_TYPE_VIS defer_lock_t {};
54249998Sdimstruct _LIBCPP_TYPE_VIS try_to_lock_t {};
55249998Sdimstruct _LIBCPP_TYPE_VIS adopt_lock_t {};
56227825Stheraven
57241903Sdim#if defined(_LIBCPP_HAS_NO_CONSTEXPR) || defined(_LIBCPP_BUILDING_MUTEX)
58227825Stheraven
59241903Sdimextern const defer_lock_t  defer_lock;
60241903Sdimextern const try_to_lock_t try_to_lock;
61241903Sdimextern const adopt_lock_t  adopt_lock;
62227825Stheraven
63241903Sdim#else
64227825Stheraven
65241903Sdimconstexpr defer_lock_t  defer_lock  = defer_lock_t();
66241903Sdimconstexpr try_to_lock_t try_to_lock = try_to_lock_t();
67241903Sdimconstexpr adopt_lock_t  adopt_lock  = adopt_lock_t();
68241903Sdim
69241903Sdim#endif
70241903Sdim
71227825Stheraventemplate <class _Mutex>
72262801Sdimclass _LIBCPP_TYPE_VIS_ONLY lock_guard
73227825Stheraven{
74227825Stheravenpublic:
75227825Stheraven    typedef _Mutex mutex_type;
76227825Stheraven
77227825Stheravenprivate:
78227825Stheraven    mutex_type& __m_;
79227825Stheravenpublic:
80227825Stheraven
81227825Stheraven    _LIBCPP_INLINE_VISIBILITY
82227825Stheraven    explicit lock_guard(mutex_type& __m)
83227825Stheraven        : __m_(__m) {__m_.lock();}
84227825Stheraven    _LIBCPP_INLINE_VISIBILITY
85227825Stheraven    lock_guard(mutex_type& __m, adopt_lock_t)
86227825Stheraven        : __m_(__m) {}
87227825Stheraven    _LIBCPP_INLINE_VISIBILITY
88227825Stheraven    ~lock_guard() {__m_.unlock();}
89227825Stheraven
90227825Stheravenprivate:
91227825Stheraven    lock_guard(lock_guard const&);// = delete;
92227825Stheraven    lock_guard& operator=(lock_guard const&);// = delete;
93227825Stheraven};
94227825Stheraven
95227825Stheraventemplate <class _Mutex>
96262801Sdimclass _LIBCPP_TYPE_VIS_ONLY unique_lock
97227825Stheraven{
98227825Stheravenpublic:
99227825Stheraven    typedef _Mutex mutex_type;
100227825Stheraven
101227825Stheravenprivate:
102227825Stheraven    mutex_type* __m_;
103227825Stheraven    bool __owns_;
104227825Stheraven
105227825Stheravenpublic:
106227825Stheraven    _LIBCPP_INLINE_VISIBILITY
107241903Sdim    unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
108227825Stheraven    _LIBCPP_INLINE_VISIBILITY
109227825Stheraven    explicit unique_lock(mutex_type& __m)
110227825Stheraven        : __m_(&__m), __owns_(true) {__m_->lock();}
111227825Stheraven    _LIBCPP_INLINE_VISIBILITY
112241903Sdim    unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
113227825Stheraven        : __m_(&__m), __owns_(false) {}
114227825Stheraven    _LIBCPP_INLINE_VISIBILITY
115227825Stheraven    unique_lock(mutex_type& __m, try_to_lock_t)
116227825Stheraven        : __m_(&__m), __owns_(__m.try_lock()) {}
117227825Stheraven    _LIBCPP_INLINE_VISIBILITY
118227825Stheraven    unique_lock(mutex_type& __m, adopt_lock_t)
119227825Stheraven        : __m_(&__m), __owns_(true) {}
120227825Stheraven    template <class _Clock, class _Duration>
121227825Stheraven    _LIBCPP_INLINE_VISIBILITY
122227825Stheraven        unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t)
123227825Stheraven            : __m_(&__m), __owns_(__m.try_lock_until(__t)) {}
124227825Stheraven    template <class _Rep, class _Period>
125227825Stheraven    _LIBCPP_INLINE_VISIBILITY
126227825Stheraven        unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
127227825Stheraven            : __m_(&__m), __owns_(__m.try_lock_for(__d)) {}
128227825Stheraven    _LIBCPP_INLINE_VISIBILITY
129227825Stheraven    ~unique_lock()
130227825Stheraven    {
131227825Stheraven        if (__owns_)
132227825Stheraven            __m_->unlock();
133227825Stheraven    }
134227825Stheraven
135227825Stheravenprivate:
136227825Stheraven    unique_lock(unique_lock const&); // = delete;
137227825Stheraven    unique_lock& operator=(unique_lock const&); // = delete;
138227825Stheraven
139227825Stheravenpublic:
140227825Stheraven#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
141227825Stheraven    _LIBCPP_INLINE_VISIBILITY
142241903Sdim    unique_lock(unique_lock&& __u) _NOEXCEPT
143227825Stheraven        : __m_(__u.__m_), __owns_(__u.__owns_)
144227825Stheraven        {__u.__m_ = nullptr; __u.__owns_ = false;}
145227825Stheraven    _LIBCPP_INLINE_VISIBILITY
146241903Sdim    unique_lock& operator=(unique_lock&& __u) _NOEXCEPT
147227825Stheraven        {
148227825Stheraven            if (__owns_)
149227825Stheraven                __m_->unlock();
150227825Stheraven            __m_ = __u.__m_;
151227825Stheraven            __owns_ = __u.__owns_;
152227825Stheraven            __u.__m_ = nullptr;
153227825Stheraven            __u.__owns_ = false;
154227825Stheraven            return *this;
155227825Stheraven        }
156227825Stheraven
157227825Stheraven#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
158227825Stheraven
159227825Stheraven    void lock();
160227825Stheraven    bool try_lock();
161227825Stheraven
162227825Stheraven    template <class _Rep, class _Period>
163227825Stheraven        bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
164227825Stheraven    template <class _Clock, class _Duration>
165227825Stheraven        bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
166227825Stheraven
167227825Stheraven    void unlock();
168227825Stheraven
169227825Stheraven    _LIBCPP_INLINE_VISIBILITY
170241903Sdim    void swap(unique_lock& __u) _NOEXCEPT
171227825Stheraven    {
172227825Stheraven        _VSTD::swap(__m_, __u.__m_);
173227825Stheraven        _VSTD::swap(__owns_, __u.__owns_);
174227825Stheraven    }
175227825Stheraven    _LIBCPP_INLINE_VISIBILITY
176241903Sdim    mutex_type* release() _NOEXCEPT
177227825Stheraven    {
178227825Stheraven        mutex_type* __m = __m_;
179227825Stheraven        __m_ = nullptr;
180227825Stheraven        __owns_ = false;
181227825Stheraven        return __m;
182227825Stheraven    }
183227825Stheraven
184227825Stheraven    _LIBCPP_INLINE_VISIBILITY
185241903Sdim    bool owns_lock() const _NOEXCEPT {return __owns_;}
186227825Stheraven    _LIBCPP_INLINE_VISIBILITY
187232950Stheraven    _LIBCPP_EXPLICIT
188241903Sdim        operator bool () const _NOEXCEPT {return __owns_;}
189227825Stheraven    _LIBCPP_INLINE_VISIBILITY
190241903Sdim    mutex_type* mutex() const _NOEXCEPT {return __m_;}
191227825Stheraven};
192227825Stheraven
193227825Stheraventemplate <class _Mutex>
194227825Stheravenvoid
195227825Stheravenunique_lock<_Mutex>::lock()
196227825Stheraven{
197227825Stheraven    if (__m_ == nullptr)
198227825Stheraven        __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
199227825Stheraven    if (__owns_)
200227825Stheraven        __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
201227825Stheraven    __m_->lock();
202227825Stheraven    __owns_ = true;
203227825Stheraven}
204227825Stheraven
205227825Stheraventemplate <class _Mutex>
206227825Stheravenbool
207227825Stheravenunique_lock<_Mutex>::try_lock()
208227825Stheraven{
209227825Stheraven    if (__m_ == nullptr)
210227825Stheraven        __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
211227825Stheraven    if (__owns_)
212227825Stheraven        __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
213227825Stheraven    __owns_ = __m_->try_lock();
214227825Stheraven    return __owns_;
215227825Stheraven}
216227825Stheraven
217227825Stheraventemplate <class _Mutex>
218227825Stheraventemplate <class _Rep, class _Period>
219227825Stheravenbool
220227825Stheravenunique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
221227825Stheraven{
222227825Stheraven    if (__m_ == nullptr)
223227825Stheraven        __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
224227825Stheraven    if (__owns_)
225227825Stheraven        __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
226227825Stheraven    __owns_ = __m_->try_lock_for(__d);
227227825Stheraven    return __owns_;
228227825Stheraven}
229227825Stheraven
230227825Stheraventemplate <class _Mutex>
231227825Stheraventemplate <class _Clock, class _Duration>
232227825Stheravenbool
233227825Stheravenunique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
234227825Stheraven{
235227825Stheraven    if (__m_ == nullptr)
236227825Stheraven        __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
237227825Stheraven    if (__owns_)
238227825Stheraven        __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
239227825Stheraven    __owns_ = __m_->try_lock_until(__t);
240227825Stheraven    return __owns_;
241227825Stheraven}
242227825Stheraven
243227825Stheraventemplate <class _Mutex>
244227825Stheravenvoid
245227825Stheravenunique_lock<_Mutex>::unlock()
246227825Stheraven{
247227825Stheraven    if (!__owns_)
248227825Stheraven        __throw_system_error(EPERM, "unique_lock::unlock: not locked");
249227825Stheraven    __m_->unlock();
250227825Stheraven    __owns_ = false;
251227825Stheraven}
252227825Stheraven
253227825Stheraventemplate <class _Mutex>
254227825Stheraveninline _LIBCPP_INLINE_VISIBILITY
255227825Stheravenvoid
256241903Sdimswap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT
257241903Sdim    {__x.swap(__y);}
258227825Stheraven
259278724Sdim//enum class cv_status
260278724Sdim_LIBCPP_DECLARE_STRONG_ENUM(cv_status)
261227825Stheraven{
262278724Sdim    no_timeout,
263278724Sdim    timeout
264227825Stheraven};
265278724Sdim_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status)
266227825Stheraven
267249998Sdimclass _LIBCPP_TYPE_VIS condition_variable
268227825Stheraven{
269227825Stheraven    pthread_cond_t __cv_;
270227825Stheravenpublic:
271227825Stheraven    _LIBCPP_INLINE_VISIBILITY
272241903Sdim#ifndef _LIBCPP_HAS_NO_CONSTEXPR
273241903Sdim    constexpr condition_variable() : __cv_(PTHREAD_COND_INITIALIZER) {}
274241903Sdim#else
275227825Stheraven    condition_variable() {__cv_ = (pthread_cond_t)PTHREAD_COND_INITIALIZER;}
276241903Sdim#endif
277227825Stheraven    ~condition_variable();
278227825Stheraven
279227825Stheravenprivate:
280227825Stheraven    condition_variable(const condition_variable&); // = delete;
281227825Stheraven    condition_variable& operator=(const condition_variable&); // = delete;
282227825Stheraven
283227825Stheravenpublic:
284241903Sdim    void notify_one() _NOEXCEPT;
285241903Sdim    void notify_all() _NOEXCEPT;
286227825Stheraven
287278724Sdim    void wait(unique_lock<mutex>& __lk) _NOEXCEPT;
288227825Stheraven    template <class _Predicate>
289227825Stheraven        void wait(unique_lock<mutex>& __lk, _Predicate __pred);
290227825Stheraven
291227825Stheraven    template <class _Clock, class _Duration>
292227825Stheraven        cv_status
293227825Stheraven        wait_until(unique_lock<mutex>& __lk,
294227825Stheraven                   const chrono::time_point<_Clock, _Duration>& __t);
295227825Stheraven
296227825Stheraven    template <class _Clock, class _Duration, class _Predicate>
297227825Stheraven        bool
298227825Stheraven        wait_until(unique_lock<mutex>& __lk,
299227825Stheraven                   const chrono::time_point<_Clock, _Duration>& __t,
300227825Stheraven                   _Predicate __pred);
301227825Stheraven
302227825Stheraven    template <class _Rep, class _Period>
303227825Stheraven        cv_status
304227825Stheraven        wait_for(unique_lock<mutex>& __lk,
305227825Stheraven                 const chrono::duration<_Rep, _Period>& __d);
306227825Stheraven
307227825Stheraven    template <class _Rep, class _Period, class _Predicate>
308227825Stheraven        bool
309227825Stheraven        wait_for(unique_lock<mutex>& __lk,
310227825Stheraven                 const chrono::duration<_Rep, _Period>& __d,
311227825Stheraven                 _Predicate __pred);
312227825Stheraven
313227825Stheraven    typedef pthread_cond_t* native_handle_type;
314227825Stheraven    _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
315227825Stheraven
316227825Stheravenprivate:
317227825Stheraven    void __do_timed_wait(unique_lock<mutex>& __lk,
318278724Sdim       chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;
319227825Stheraven};
320278724Sdim#endif // !_LIBCPP_HAS_NO_THREADS
321227825Stheraven
322227825Stheraventemplate <class _To, class _Rep, class _Period>
323227825Stheraveninline _LIBCPP_INLINE_VISIBILITY
324227825Stheraventypename enable_if
325227825Stheraven<
326227825Stheraven    chrono::__is_duration<_To>::value,
327227825Stheraven    _To
328227825Stheraven>::type
329227825Stheraven__ceil(chrono::duration<_Rep, _Period> __d)
330227825Stheraven{
331227825Stheraven    using namespace chrono;
332227825Stheraven    _To __r = duration_cast<_To>(__d);
333227825Stheraven    if (__r < __d)
334227825Stheraven        ++__r;
335227825Stheraven    return __r;
336227825Stheraven}
337227825Stheraven
338278724Sdim#ifndef _LIBCPP_HAS_NO_THREADS
339227825Stheraventemplate <class _Predicate>
340227825Stheravenvoid
341227825Stheravencondition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
342227825Stheraven{
343227825Stheraven    while (!__pred())
344227825Stheraven        wait(__lk);
345227825Stheraven}
346227825Stheraven
347227825Stheraventemplate <class _Clock, class _Duration>
348227825Stheravencv_status
349227825Stheravencondition_variable::wait_until(unique_lock<mutex>& __lk,
350227825Stheraven                               const chrono::time_point<_Clock, _Duration>& __t)
351227825Stheraven{
352227825Stheraven    using namespace chrono;
353241903Sdim    wait_for(__lk, __t - _Clock::now());
354227825Stheraven    return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
355227825Stheraven}
356227825Stheraven
357227825Stheraventemplate <class _Clock, class _Duration, class _Predicate>
358227825Stheravenbool
359227825Stheravencondition_variable::wait_until(unique_lock<mutex>& __lk,
360227825Stheraven                   const chrono::time_point<_Clock, _Duration>& __t,
361227825Stheraven                   _Predicate __pred)
362227825Stheraven{
363227825Stheraven    while (!__pred())
364227825Stheraven    {
365227825Stheraven        if (wait_until(__lk, __t) == cv_status::timeout)
366227825Stheraven            return __pred();
367227825Stheraven    }
368227825Stheraven    return true;
369227825Stheraven}
370227825Stheraven
371227825Stheraventemplate <class _Rep, class _Period>
372227825Stheravencv_status
373227825Stheravencondition_variable::wait_for(unique_lock<mutex>& __lk,
374227825Stheraven                             const chrono::duration<_Rep, _Period>& __d)
375227825Stheraven{
376227825Stheraven    using namespace chrono;
377241903Sdim    if (__d <= __d.zero())
378241903Sdim        return cv_status::timeout;
379241903Sdim    typedef time_point<system_clock, duration<long double, nano> > __sys_tpf;
380241903Sdim    typedef time_point<system_clock, nanoseconds> __sys_tpi;
381241903Sdim    __sys_tpf _Max = __sys_tpi::max();
382227825Stheraven    system_clock::time_point __s_now = system_clock::now();
383227825Stheraven    steady_clock::time_point __c_now = steady_clock::now();
384241903Sdim    if (_Max - __d > __s_now)
385241903Sdim        __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d));
386241903Sdim    else
387241903Sdim        __do_timed_wait(__lk, __sys_tpi::max());
388227825Stheraven    return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
389227825Stheraven                                                 cv_status::timeout;
390227825Stheraven}
391227825Stheraven
392227825Stheraventemplate <class _Rep, class _Period, class _Predicate>
393227825Stheraveninline _LIBCPP_INLINE_VISIBILITY
394227825Stheravenbool
395227825Stheravencondition_variable::wait_for(unique_lock<mutex>& __lk,
396227825Stheraven                             const chrono::duration<_Rep, _Period>& __d,
397227825Stheraven                             _Predicate __pred)
398227825Stheraven{
399227825Stheraven    return wait_until(__lk, chrono::steady_clock::now() + __d,
400227825Stheraven                      _VSTD::move(__pred));
401227825Stheraven}
402227825Stheraven
403278724Sdim#endif // !_LIBCPP_HAS_NO_THREADS
404278724Sdim
405227825Stheraven_LIBCPP_END_NAMESPACE_STD
406227825Stheraven
407227825Stheraven#endif  // _LIBCPP___MUTEX_BASE
408