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