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