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