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