__mutex_base revision 262801
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
25249998Sdimclass _LIBCPP_TYPE_VIS mutex
26227825Stheraven{
27227825Stheraven    pthread_mutex_t __m_;
28227825Stheraven
29227825Stheravenpublic:
30227825Stheraven    _LIBCPP_INLINE_VISIBILITY
31241903Sdim#ifndef _LIBCPP_HAS_NO_CONSTEXPR
32241903Sdim     constexpr mutex() _NOEXCEPT : __m_(PTHREAD_MUTEX_INITIALIZER) {}
33241903Sdim#else
34241903Sdim     mutex() _NOEXCEPT {__m_ = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;}
35241903Sdim#endif
36227825Stheraven     ~mutex();
37227825Stheraven
38227825Stheravenprivate:
39227825Stheraven    mutex(const mutex&);// = delete;
40227825Stheraven    mutex& operator=(const mutex&);// = delete;
41227825Stheraven
42227825Stheravenpublic:
43227825Stheraven    void lock();
44241903Sdim    bool try_lock() _NOEXCEPT;
45241903Sdim    void unlock() _NOEXCEPT;
46227825Stheraven
47227825Stheraven    typedef pthread_mutex_t* native_handle_type;
48227825Stheraven    _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
49227825Stheraven};
50227825Stheraven
51249998Sdimstruct _LIBCPP_TYPE_VIS defer_lock_t {};
52249998Sdimstruct _LIBCPP_TYPE_VIS try_to_lock_t {};
53249998Sdimstruct _LIBCPP_TYPE_VIS adopt_lock_t {};
54227825Stheraven
55241903Sdim#if defined(_LIBCPP_HAS_NO_CONSTEXPR) || defined(_LIBCPP_BUILDING_MUTEX)
56227825Stheraven
57241903Sdimextern const defer_lock_t  defer_lock;
58241903Sdimextern const try_to_lock_t try_to_lock;
59241903Sdimextern const adopt_lock_t  adopt_lock;
60227825Stheraven
61241903Sdim#else
62227825Stheraven
63241903Sdimconstexpr defer_lock_t  defer_lock  = defer_lock_t();
64241903Sdimconstexpr try_to_lock_t try_to_lock = try_to_lock_t();
65241903Sdimconstexpr adopt_lock_t  adopt_lock  = adopt_lock_t();
66241903Sdim
67241903Sdim#endif
68241903Sdim
69227825Stheraventemplate <class _Mutex>
70262801Sdimclass _LIBCPP_TYPE_VIS_ONLY lock_guard
71227825Stheraven{
72227825Stheravenpublic:
73227825Stheraven    typedef _Mutex mutex_type;
74227825Stheraven
75227825Stheravenprivate:
76227825Stheraven    mutex_type& __m_;
77227825Stheravenpublic:
78227825Stheraven
79227825Stheraven    _LIBCPP_INLINE_VISIBILITY
80227825Stheraven    explicit lock_guard(mutex_type& __m)
81227825Stheraven        : __m_(__m) {__m_.lock();}
82227825Stheraven    _LIBCPP_INLINE_VISIBILITY
83227825Stheraven    lock_guard(mutex_type& __m, adopt_lock_t)
84227825Stheraven        : __m_(__m) {}
85227825Stheraven    _LIBCPP_INLINE_VISIBILITY
86227825Stheraven    ~lock_guard() {__m_.unlock();}
87227825Stheraven
88227825Stheravenprivate:
89227825Stheraven    lock_guard(lock_guard const&);// = delete;
90227825Stheraven    lock_guard& operator=(lock_guard const&);// = delete;
91227825Stheraven};
92227825Stheraven
93227825Stheraventemplate <class _Mutex>
94262801Sdimclass _LIBCPP_TYPE_VIS_ONLY unique_lock
95227825Stheraven{
96227825Stheravenpublic:
97227825Stheraven    typedef _Mutex mutex_type;
98227825Stheraven
99227825Stheravenprivate:
100227825Stheraven    mutex_type* __m_;
101227825Stheraven    bool __owns_;
102227825Stheraven
103227825Stheravenpublic:
104227825Stheraven    _LIBCPP_INLINE_VISIBILITY
105241903Sdim    unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
106227825Stheraven    _LIBCPP_INLINE_VISIBILITY
107227825Stheraven    explicit unique_lock(mutex_type& __m)
108227825Stheraven        : __m_(&__m), __owns_(true) {__m_->lock();}
109227825Stheraven    _LIBCPP_INLINE_VISIBILITY
110241903Sdim    unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
111227825Stheraven        : __m_(&__m), __owns_(false) {}
112227825Stheraven    _LIBCPP_INLINE_VISIBILITY
113227825Stheraven    unique_lock(mutex_type& __m, try_to_lock_t)
114227825Stheraven        : __m_(&__m), __owns_(__m.try_lock()) {}
115227825Stheraven    _LIBCPP_INLINE_VISIBILITY
116227825Stheraven    unique_lock(mutex_type& __m, adopt_lock_t)
117227825Stheraven        : __m_(&__m), __owns_(true) {}
118227825Stheraven    template <class _Clock, class _Duration>
119227825Stheraven    _LIBCPP_INLINE_VISIBILITY
120227825Stheraven        unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t)
121227825Stheraven            : __m_(&__m), __owns_(__m.try_lock_until(__t)) {}
122227825Stheraven    template <class _Rep, class _Period>
123227825Stheraven    _LIBCPP_INLINE_VISIBILITY
124227825Stheraven        unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
125227825Stheraven            : __m_(&__m), __owns_(__m.try_lock_for(__d)) {}
126227825Stheraven    _LIBCPP_INLINE_VISIBILITY
127227825Stheraven    ~unique_lock()
128227825Stheraven    {
129227825Stheraven        if (__owns_)
130227825Stheraven            __m_->unlock();
131227825Stheraven    }
132227825Stheraven
133227825Stheravenprivate:
134227825Stheraven    unique_lock(unique_lock const&); // = delete;
135227825Stheraven    unique_lock& operator=(unique_lock const&); // = delete;
136227825Stheraven
137227825Stheravenpublic:
138227825Stheraven#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
139227825Stheraven    _LIBCPP_INLINE_VISIBILITY
140241903Sdim    unique_lock(unique_lock&& __u) _NOEXCEPT
141227825Stheraven        : __m_(__u.__m_), __owns_(__u.__owns_)
142227825Stheraven        {__u.__m_ = nullptr; __u.__owns_ = false;}
143227825Stheraven    _LIBCPP_INLINE_VISIBILITY
144241903Sdim    unique_lock& operator=(unique_lock&& __u) _NOEXCEPT
145227825Stheraven        {
146227825Stheraven            if (__owns_)
147227825Stheraven                __m_->unlock();
148227825Stheraven            __m_ = __u.__m_;
149227825Stheraven            __owns_ = __u.__owns_;
150227825Stheraven            __u.__m_ = nullptr;
151227825Stheraven            __u.__owns_ = false;
152227825Stheraven            return *this;
153227825Stheraven        }
154227825Stheraven
155227825Stheraven#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
156227825Stheraven
157227825Stheraven    void lock();
158227825Stheraven    bool try_lock();
159227825Stheraven
160227825Stheraven    template <class _Rep, class _Period>
161227825Stheraven        bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
162227825Stheraven    template <class _Clock, class _Duration>
163227825Stheraven        bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
164227825Stheraven
165227825Stheraven    void unlock();
166227825Stheraven
167227825Stheraven    _LIBCPP_INLINE_VISIBILITY
168241903Sdim    void swap(unique_lock& __u) _NOEXCEPT
169227825Stheraven    {
170227825Stheraven        _VSTD::swap(__m_, __u.__m_);
171227825Stheraven        _VSTD::swap(__owns_, __u.__owns_);
172227825Stheraven    }
173227825Stheraven    _LIBCPP_INLINE_VISIBILITY
174241903Sdim    mutex_type* release() _NOEXCEPT
175227825Stheraven    {
176227825Stheraven        mutex_type* __m = __m_;
177227825Stheraven        __m_ = nullptr;
178227825Stheraven        __owns_ = false;
179227825Stheraven        return __m;
180227825Stheraven    }
181227825Stheraven
182227825Stheraven    _LIBCPP_INLINE_VISIBILITY
183241903Sdim    bool owns_lock() const _NOEXCEPT {return __owns_;}
184227825Stheraven    _LIBCPP_INLINE_VISIBILITY
185232950Stheraven    _LIBCPP_EXPLICIT
186241903Sdim        operator bool () const _NOEXCEPT {return __owns_;}
187227825Stheraven    _LIBCPP_INLINE_VISIBILITY
188241903Sdim    mutex_type* mutex() const _NOEXCEPT {return __m_;}
189227825Stheraven};
190227825Stheraven
191227825Stheraventemplate <class _Mutex>
192227825Stheravenvoid
193227825Stheravenunique_lock<_Mutex>::lock()
194227825Stheraven{
195227825Stheraven    if (__m_ == nullptr)
196227825Stheraven        __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
197227825Stheraven    if (__owns_)
198227825Stheraven        __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
199227825Stheraven    __m_->lock();
200227825Stheraven    __owns_ = true;
201227825Stheraven}
202227825Stheraven
203227825Stheraventemplate <class _Mutex>
204227825Stheravenbool
205227825Stheravenunique_lock<_Mutex>::try_lock()
206227825Stheraven{
207227825Stheraven    if (__m_ == nullptr)
208227825Stheraven        __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
209227825Stheraven    if (__owns_)
210227825Stheraven        __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
211227825Stheraven    __owns_ = __m_->try_lock();
212227825Stheraven    return __owns_;
213227825Stheraven}
214227825Stheraven
215227825Stheraventemplate <class _Mutex>
216227825Stheraventemplate <class _Rep, class _Period>
217227825Stheravenbool
218227825Stheravenunique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
219227825Stheraven{
220227825Stheraven    if (__m_ == nullptr)
221227825Stheraven        __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
222227825Stheraven    if (__owns_)
223227825Stheraven        __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
224227825Stheraven    __owns_ = __m_->try_lock_for(__d);
225227825Stheraven    return __owns_;
226227825Stheraven}
227227825Stheraven
228227825Stheraventemplate <class _Mutex>
229227825Stheraventemplate <class _Clock, class _Duration>
230227825Stheravenbool
231227825Stheravenunique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
232227825Stheraven{
233227825Stheraven    if (__m_ == nullptr)
234227825Stheraven        __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
235227825Stheraven    if (__owns_)
236227825Stheraven        __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
237227825Stheraven    __owns_ = __m_->try_lock_until(__t);
238227825Stheraven    return __owns_;
239227825Stheraven}
240227825Stheraven
241227825Stheraventemplate <class _Mutex>
242227825Stheravenvoid
243227825Stheravenunique_lock<_Mutex>::unlock()
244227825Stheraven{
245227825Stheraven    if (!__owns_)
246227825Stheraven        __throw_system_error(EPERM, "unique_lock::unlock: not locked");
247227825Stheraven    __m_->unlock();
248227825Stheraven    __owns_ = false;
249227825Stheraven}
250227825Stheraven
251227825Stheraventemplate <class _Mutex>
252227825Stheraveninline _LIBCPP_INLINE_VISIBILITY
253227825Stheravenvoid
254241903Sdimswap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT
255241903Sdim    {__x.swap(__y);}
256227825Stheraven
257249998Sdimstruct _LIBCPP_TYPE_VIS cv_status
258227825Stheraven{
259242945Stheraven    enum __lx {
260227825Stheraven        no_timeout,
261227825Stheraven        timeout
262227825Stheraven    };
263227825Stheraven
264242945Stheraven    __lx __v_;
265227825Stheraven
266242945Stheraven    _LIBCPP_INLINE_VISIBILITY cv_status(__lx __v) : __v_(__v) {}
267227825Stheraven    _LIBCPP_INLINE_VISIBILITY operator int() const {return __v_;}
268227825Stheraven
269227825Stheraven};
270227825Stheraven
271249998Sdimclass _LIBCPP_TYPE_VIS condition_variable
272227825Stheraven{
273227825Stheraven    pthread_cond_t __cv_;
274227825Stheravenpublic:
275227825Stheraven    _LIBCPP_INLINE_VISIBILITY
276241903Sdim#ifndef _LIBCPP_HAS_NO_CONSTEXPR
277241903Sdim    constexpr condition_variable() : __cv_(PTHREAD_COND_INITIALIZER) {}
278241903Sdim#else
279227825Stheraven    condition_variable() {__cv_ = (pthread_cond_t)PTHREAD_COND_INITIALIZER;}
280241903Sdim#endif
281227825Stheraven    ~condition_variable();
282227825Stheraven
283227825Stheravenprivate:
284227825Stheraven    condition_variable(const condition_variable&); // = delete;
285227825Stheraven    condition_variable& operator=(const condition_variable&); // = delete;
286227825Stheraven
287227825Stheravenpublic:
288241903Sdim    void notify_one() _NOEXCEPT;
289241903Sdim    void notify_all() _NOEXCEPT;
290227825Stheraven
291227825Stheraven    void wait(unique_lock<mutex>& __lk);
292227825Stheraven    template <class _Predicate>
293227825Stheraven        void wait(unique_lock<mutex>& __lk, _Predicate __pred);
294227825Stheraven
295227825Stheraven    template <class _Clock, class _Duration>
296227825Stheraven        cv_status
297227825Stheraven        wait_until(unique_lock<mutex>& __lk,
298227825Stheraven                   const chrono::time_point<_Clock, _Duration>& __t);
299227825Stheraven
300227825Stheraven    template <class _Clock, class _Duration, class _Predicate>
301227825Stheraven        bool
302227825Stheraven        wait_until(unique_lock<mutex>& __lk,
303227825Stheraven                   const chrono::time_point<_Clock, _Duration>& __t,
304227825Stheraven                   _Predicate __pred);
305227825Stheraven
306227825Stheraven    template <class _Rep, class _Period>
307227825Stheraven        cv_status
308227825Stheraven        wait_for(unique_lock<mutex>& __lk,
309227825Stheraven                 const chrono::duration<_Rep, _Period>& __d);
310227825Stheraven
311227825Stheraven    template <class _Rep, class _Period, class _Predicate>
312227825Stheraven        bool
313227825Stheraven        wait_for(unique_lock<mutex>& __lk,
314227825Stheraven                 const chrono::duration<_Rep, _Period>& __d,
315227825Stheraven                 _Predicate __pred);
316227825Stheraven
317227825Stheraven    typedef pthread_cond_t* native_handle_type;
318227825Stheraven    _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
319227825Stheraven
320227825Stheravenprivate:
321227825Stheraven    void __do_timed_wait(unique_lock<mutex>& __lk,
322227825Stheraven                 chrono::time_point<chrono::system_clock, chrono::nanoseconds>);
323227825Stheraven};
324227825Stheraven
325227825Stheraventemplate <class _To, class _Rep, class _Period>
326227825Stheraveninline _LIBCPP_INLINE_VISIBILITY
327227825Stheraventypename enable_if
328227825Stheraven<
329227825Stheraven    chrono::__is_duration<_To>::value,
330227825Stheraven    _To
331227825Stheraven>::type
332227825Stheraven__ceil(chrono::duration<_Rep, _Period> __d)
333227825Stheraven{
334227825Stheraven    using namespace chrono;
335227825Stheraven    _To __r = duration_cast<_To>(__d);
336227825Stheraven    if (__r < __d)
337227825Stheraven        ++__r;
338227825Stheraven    return __r;
339227825Stheraven}
340227825Stheraven
341227825Stheraventemplate <class _Predicate>
342227825Stheravenvoid
343227825Stheravencondition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
344227825Stheraven{
345227825Stheraven    while (!__pred())
346227825Stheraven        wait(__lk);
347227825Stheraven}
348227825Stheraven
349227825Stheraventemplate <class _Clock, class _Duration>
350227825Stheravencv_status
351227825Stheravencondition_variable::wait_until(unique_lock<mutex>& __lk,
352227825Stheraven                               const chrono::time_point<_Clock, _Duration>& __t)
353227825Stheraven{
354227825Stheraven    using namespace chrono;
355241903Sdim    wait_for(__lk, __t - _Clock::now());
356227825Stheraven    return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
357227825Stheraven}
358227825Stheraven
359227825Stheraventemplate <class _Clock, class _Duration, class _Predicate>
360227825Stheravenbool
361227825Stheravencondition_variable::wait_until(unique_lock<mutex>& __lk,
362227825Stheraven                   const chrono::time_point<_Clock, _Duration>& __t,
363227825Stheraven                   _Predicate __pred)
364227825Stheraven{
365227825Stheraven    while (!__pred())
366227825Stheraven    {
367227825Stheraven        if (wait_until(__lk, __t) == cv_status::timeout)
368227825Stheraven            return __pred();
369227825Stheraven    }
370227825Stheraven    return true;
371227825Stheraven}
372227825Stheraven
373227825Stheraventemplate <class _Rep, class _Period>
374227825Stheravencv_status
375227825Stheravencondition_variable::wait_for(unique_lock<mutex>& __lk,
376227825Stheraven                             const chrono::duration<_Rep, _Period>& __d)
377227825Stheraven{
378227825Stheraven    using namespace chrono;
379241903Sdim    if (__d <= __d.zero())
380241903Sdim        return cv_status::timeout;
381241903Sdim    typedef time_point<system_clock, duration<long double, nano> > __sys_tpf;
382241903Sdim    typedef time_point<system_clock, nanoseconds> __sys_tpi;
383241903Sdim    __sys_tpf _Max = __sys_tpi::max();
384227825Stheraven    system_clock::time_point __s_now = system_clock::now();
385227825Stheraven    steady_clock::time_point __c_now = steady_clock::now();
386241903Sdim    if (_Max - __d > __s_now)
387241903Sdim        __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d));
388241903Sdim    else
389241903Sdim        __do_timed_wait(__lk, __sys_tpi::max());
390227825Stheraven    return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
391227825Stheraven                                                 cv_status::timeout;
392227825Stheraven}
393227825Stheraven
394227825Stheraventemplate <class _Rep, class _Period, class _Predicate>
395227825Stheraveninline _LIBCPP_INLINE_VISIBILITY
396227825Stheravenbool
397227825Stheravencondition_variable::wait_for(unique_lock<mutex>& __lk,
398227825Stheraven                             const chrono::duration<_Rep, _Period>& __d,
399227825Stheraven                             _Predicate __pred)
400227825Stheraven{
401227825Stheraven    return wait_until(__lk, chrono::steady_clock::now() + __d,
402227825Stheraven                      _VSTD::move(__pred));
403227825Stheraven}
404227825Stheraven
405227825Stheraven_LIBCPP_END_NAMESPACE_STD
406227825Stheraven
407227825Stheraven#endif  // _LIBCPP___MUTEX_BASE
408