__mutex_base revision 232924
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#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
20#pragma GCC system_header
21#endif
22
23#ifdef _LIBCPP_SHARED_LOCK
24
25namespace ting {
26template <class _Mutex> class shared_lock;
27template <class _Mutex> class upgrade_lock;
28}
29
30#endif  // _LIBCPP_SHARED_LOCK
31
32
33_LIBCPP_BEGIN_NAMESPACE_STD
34
35class _LIBCPP_VISIBLE mutex
36{
37    pthread_mutex_t __m_;
38
39public:
40    _LIBCPP_INLINE_VISIBILITY
41     mutex() {__m_ = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;}
42     ~mutex();
43
44private:
45    mutex(const mutex&);// = delete;
46    mutex& operator=(const mutex&);// = delete;
47
48public:
49    void lock();
50    bool try_lock();
51    void unlock();
52
53    typedef pthread_mutex_t* native_handle_type;
54    _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
55};
56
57struct _LIBCPP_VISIBLE defer_lock_t {};
58struct _LIBCPP_VISIBLE try_to_lock_t {};
59struct _LIBCPP_VISIBLE adopt_lock_t {};
60
61//constexpr
62extern const
63defer_lock_t  defer_lock;
64
65//constexpr
66extern const
67try_to_lock_t try_to_lock;
68
69//constexpr
70extern const
71adopt_lock_t  adopt_lock;
72
73template <class _Mutex>
74class _LIBCPP_VISIBLE 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_VISIBLE 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() : __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)
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)
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)
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#ifdef _LIBCPP_SHARED_LOCK
160
161    unique_lock(ting::shared_lock<mutex_type>&&, try_to_lock_t);
162    template <class _Clock, class _Duration>
163        unique_lock(ting::shared_lock<mutex_type>&&,
164                    const chrono::time_point<_Clock, _Duration>&);
165    template <class _Rep, class _Period>
166        unique_lock(ting::shared_lock<mutex_type>&&,
167                    const chrono::duration<_Rep, _Period>&);
168
169    explicit unique_lock(ting::upgrade_lock<mutex_type>&&);
170    unique_lock(ting::upgrade_lock<mutex_type>&&, try_to_lock_t);
171    template <class _Clock, class _Duration>
172        unique_lock(ting::upgrade_lock<mutex_type>&&,
173                    const chrono::time_point<_Clock, _Duration>&);
174    template <class _Rep, class _Period>
175        unique_lock(ting::upgrade_lock<mutex_type>&&,
176                    const chrono::duration<_Rep, _Period>&);
177
178#endif  // _LIBCPP_SHARED_LOCK
179
180#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
181
182    void lock();
183    bool try_lock();
184
185    template <class _Rep, class _Period>
186        bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
187    template <class _Clock, class _Duration>
188        bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
189
190    void unlock();
191
192    _LIBCPP_INLINE_VISIBILITY
193    void swap(unique_lock& __u)
194    {
195        _VSTD::swap(__m_, __u.__m_);
196        _VSTD::swap(__owns_, __u.__owns_);
197    }
198    _LIBCPP_INLINE_VISIBILITY
199    mutex_type* release()
200    {
201        mutex_type* __m = __m_;
202        __m_ = nullptr;
203        __owns_ = false;
204        return __m;
205    }
206
207    _LIBCPP_INLINE_VISIBILITY
208    bool owns_lock() const {return __owns_;}
209    _LIBCPP_INLINE_VISIBILITY
210    _LIBCPP_EXPLICIT
211        operator bool () const {return __owns_;}
212    _LIBCPP_INLINE_VISIBILITY
213    mutex_type* mutex() const {return __m_;}
214};
215
216template <class _Mutex>
217void
218unique_lock<_Mutex>::lock()
219{
220    if (__m_ == nullptr)
221        __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
222    if (__owns_)
223        __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
224    __m_->lock();
225    __owns_ = true;
226}
227
228template <class _Mutex>
229bool
230unique_lock<_Mutex>::try_lock()
231{
232    if (__m_ == nullptr)
233        __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
234    if (__owns_)
235        __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
236    __owns_ = __m_->try_lock();
237    return __owns_;
238}
239
240template <class _Mutex>
241template <class _Rep, class _Period>
242bool
243unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
244{
245    if (__m_ == nullptr)
246        __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
247    if (__owns_)
248        __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
249    __owns_ = __m_->try_lock_for(__d);
250    return __owns_;
251}
252
253template <class _Mutex>
254template <class _Clock, class _Duration>
255bool
256unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
257{
258    if (__m_ == nullptr)
259        __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
260    if (__owns_)
261        __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
262    __owns_ = __m_->try_lock_until(__t);
263    return __owns_;
264}
265
266template <class _Mutex>
267void
268unique_lock<_Mutex>::unlock()
269{
270    if (!__owns_)
271        __throw_system_error(EPERM, "unique_lock::unlock: not locked");
272    __m_->unlock();
273    __owns_ = false;
274}
275
276template <class _Mutex>
277inline _LIBCPP_INLINE_VISIBILITY
278void
279swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) {__x.swap(__y);}
280
281struct _LIBCPP_VISIBLE cv_status
282{
283    enum _ {
284        no_timeout,
285        timeout
286    };
287
288    _ __v_;
289
290    _LIBCPP_INLINE_VISIBILITY cv_status(_ __v) : __v_(__v) {}
291    _LIBCPP_INLINE_VISIBILITY operator int() const {return __v_;}
292
293};
294
295class _LIBCPP_VISIBLE condition_variable
296{
297    pthread_cond_t __cv_;
298public:
299    _LIBCPP_INLINE_VISIBILITY
300    condition_variable() {__cv_ = (pthread_cond_t)PTHREAD_COND_INITIALIZER;}
301    ~condition_variable();
302
303private:
304    condition_variable(const condition_variable&); // = delete;
305    condition_variable& operator=(const condition_variable&); // = delete;
306
307public:
308    void notify_one();
309    void notify_all();
310
311    void wait(unique_lock<mutex>& __lk);
312    template <class _Predicate>
313        void wait(unique_lock<mutex>& __lk, _Predicate __pred);
314
315    template <class _Duration>
316        cv_status
317        wait_until(unique_lock<mutex>& __lk,
318                   const chrono::time_point<chrono::system_clock, _Duration>& __t);
319
320    template <class _Clock, class _Duration>
321        cv_status
322        wait_until(unique_lock<mutex>& __lk,
323                   const chrono::time_point<_Clock, _Duration>& __t);
324
325    template <class _Clock, class _Duration, class _Predicate>
326        bool
327        wait_until(unique_lock<mutex>& __lk,
328                   const chrono::time_point<_Clock, _Duration>& __t,
329                   _Predicate __pred);
330
331    template <class _Rep, class _Period>
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        wait_for(unique_lock<mutex>& __lk,
339                 const chrono::duration<_Rep, _Period>& __d,
340                 _Predicate __pred);
341
342    typedef pthread_cond_t* native_handle_type;
343    _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
344
345private:
346    void __do_timed_wait(unique_lock<mutex>& __lk,
347                 chrono::time_point<chrono::system_clock, chrono::nanoseconds>);
348};
349
350template <class _To, class _Rep, class _Period>
351inline _LIBCPP_INLINE_VISIBILITY
352typename enable_if
353<
354    chrono::__is_duration<_To>::value,
355    _To
356>::type
357__ceil(chrono::duration<_Rep, _Period> __d)
358{
359    using namespace chrono;
360    _To __r = duration_cast<_To>(__d);
361    if (__r < __d)
362        ++__r;
363    return __r;
364}
365
366template <class _Predicate>
367void
368condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
369{
370    while (!__pred())
371        wait(__lk);
372}
373
374template <class _Duration>
375cv_status
376condition_variable::wait_until(unique_lock<mutex>& __lk,
377                 const chrono::time_point<chrono::system_clock, _Duration>& __t)
378{
379    using namespace chrono;
380    typedef time_point<system_clock, nanoseconds> __nano_sys_tmpt;
381    __do_timed_wait(__lk,
382                  __nano_sys_tmpt(__ceil<nanoseconds>(__t.time_since_epoch())));
383    return system_clock::now() < __t ? cv_status::no_timeout :
384                                       cv_status::timeout;
385}
386
387template <class _Clock, class _Duration>
388cv_status
389condition_variable::wait_until(unique_lock<mutex>& __lk,
390                               const chrono::time_point<_Clock, _Duration>& __t)
391{
392    using namespace chrono;
393    system_clock::time_point     __s_now = system_clock::now();
394    typename _Clock::time_point  __c_now = _Clock::now();
395    __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__t - __c_now));
396    return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
397}
398
399template <class _Clock, class _Duration, class _Predicate>
400bool
401condition_variable::wait_until(unique_lock<mutex>& __lk,
402                   const chrono::time_point<_Clock, _Duration>& __t,
403                   _Predicate __pred)
404{
405    while (!__pred())
406    {
407        if (wait_until(__lk, __t) == cv_status::timeout)
408            return __pred();
409    }
410    return true;
411}
412
413template <class _Rep, class _Period>
414cv_status
415condition_variable::wait_for(unique_lock<mutex>& __lk,
416                             const chrono::duration<_Rep, _Period>& __d)
417{
418    using namespace chrono;
419    system_clock::time_point __s_now = system_clock::now();
420    steady_clock::time_point __c_now = steady_clock::now();
421    __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d));
422    return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
423                                                 cv_status::timeout;
424}
425
426template <class _Rep, class _Period, class _Predicate>
427inline _LIBCPP_INLINE_VISIBILITY
428bool
429condition_variable::wait_for(unique_lock<mutex>& __lk,
430                             const chrono::duration<_Rep, _Period>& __d,
431                             _Predicate __pred)
432{
433    return wait_until(__lk, chrono::steady_clock::now() + __d,
434                      _VSTD::move(__pred));
435}
436
437_LIBCPP_END_NAMESPACE_STD
438
439#endif  // _LIBCPP___MUTEX_BASE
440