blob: d4023a64f9faf2424d535bb1de68d76a81bf8c38 [file] [log] [blame]
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
Howard Hinnantf5256e12010-05-11 21:36:01 +00004// The LLVM Compiler Infrastructure
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00005//
Howard Hinnantb64f8b02010-11-16 22:09:02 +00006// This file is dual licensed under the MIT and the University of Illinois Open
7// Source Licenses. See LICENSE.TXT for details.
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00008//
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
Howard Hinnant08e17472011-10-17 20:05:10 +000019#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000020#pragma GCC system_header
Howard Hinnant08e17472011-10-17 20:05:10 +000021#endif
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000022
23_LIBCPP_BEGIN_NAMESPACE_STD
24
Howard Hinnant83eade62013-03-06 23:30:19 +000025class _LIBCPP_TYPE_VIS mutex
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000026{
27 pthread_mutex_t __m_;
28
29public:
Howard Hinnant333f50d2010-09-21 20:16:37 +000030 _LIBCPP_INLINE_VISIBILITY
Howard Hinnant384608e2012-07-07 20:01:52 +000031#ifndef _LIBCPP_HAS_NO_CONSTEXPR
Howard Hinnant5c90cba2012-09-11 16:10:20 +000032 constexpr mutex() _NOEXCEPT : __m_(PTHREAD_MUTEX_INITIALIZER) {}
Howard Hinnant384608e2012-07-07 20:01:52 +000033#else
Howard Hinnant499c61f2012-07-21 16:13:09 +000034 mutex() _NOEXCEPT {__m_ = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;}
Howard Hinnant384608e2012-07-07 20:01:52 +000035#endif
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000036 ~mutex();
37
38private:
39 mutex(const mutex&);// = delete;
40 mutex& operator=(const mutex&);// = delete;
41
42public:
43 void lock();
Howard Hinnant499c61f2012-07-21 16:13:09 +000044 bool try_lock() _NOEXCEPT;
45 void unlock() _NOEXCEPT;
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000046
47 typedef pthread_mutex_t* native_handle_type;
Howard Hinnant333f50d2010-09-21 20:16:37 +000048 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000049};
50
Howard Hinnant83eade62013-03-06 23:30:19 +000051struct _LIBCPP_TYPE_VIS defer_lock_t {};
52struct _LIBCPP_TYPE_VIS try_to_lock_t {};
53struct _LIBCPP_TYPE_VIS adopt_lock_t {};
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000054
Howard Hinnant499c61f2012-07-21 16:13:09 +000055#if defined(_LIBCPP_HAS_NO_CONSTEXPR) || defined(_LIBCPP_BUILDING_MUTEX)
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000056
Howard Hinnant499c61f2012-07-21 16:13:09 +000057extern const defer_lock_t defer_lock;
58extern const try_to_lock_t try_to_lock;
59extern const adopt_lock_t adopt_lock;
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000060
Howard Hinnant499c61f2012-07-21 16:13:09 +000061#else
62
63constexpr defer_lock_t defer_lock = defer_lock_t();
64constexpr try_to_lock_t try_to_lock = try_to_lock_t();
65constexpr adopt_lock_t adopt_lock = adopt_lock_t();
66
67#endif
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000068
69template <class _Mutex>
Howard Hinnant0f678bd2013-08-12 18:38:34 +000070class _LIBCPP_TYPE_VIS_ONLY lock_guard
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000071{
72public:
73 typedef _Mutex mutex_type;
74
75private:
76 mutex_type& __m_;
77public:
78
Howard Hinnant333f50d2010-09-21 20:16:37 +000079 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000080 explicit lock_guard(mutex_type& __m)
81 : __m_(__m) {__m_.lock();}
Howard Hinnant333f50d2010-09-21 20:16:37 +000082 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000083 lock_guard(mutex_type& __m, adopt_lock_t)
84 : __m_(__m) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +000085 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000086 ~lock_guard() {__m_.unlock();}
87
88private:
89 lock_guard(lock_guard const&);// = delete;
90 lock_guard& operator=(lock_guard const&);// = delete;
91};
92
93template <class _Mutex>
Howard Hinnant0f678bd2013-08-12 18:38:34 +000094class _LIBCPP_TYPE_VIS_ONLY unique_lock
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000095{
96public:
97 typedef _Mutex mutex_type;
98
99private:
100 mutex_type* __m_;
101 bool __owns_;
102
103public:
Howard Hinnant333f50d2010-09-21 20:16:37 +0000104 _LIBCPP_INLINE_VISIBILITY
Howard Hinnant499c61f2012-07-21 16:13:09 +0000105 unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000106 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000107 explicit unique_lock(mutex_type& __m)
108 : __m_(&__m), __owns_(true) {__m_->lock();}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000109 _LIBCPP_INLINE_VISIBILITY
Howard Hinnant499c61f2012-07-21 16:13:09 +0000110 unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000111 : __m_(&__m), __owns_(false) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000112 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000113 unique_lock(mutex_type& __m, try_to_lock_t)
114 : __m_(&__m), __owns_(__m.try_lock()) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000115 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000116 unique_lock(mutex_type& __m, adopt_lock_t)
117 : __m_(&__m), __owns_(true) {}
118 template <class _Clock, class _Duration>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000119 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000120 unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t)
121 : __m_(&__m), __owns_(__m.try_lock_until(__t)) {}
122 template <class _Rep, class _Period>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000123 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000124 unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
125 : __m_(&__m), __owns_(__m.try_lock_for(__d)) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000126 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000127 ~unique_lock()
128 {
129 if (__owns_)
130 __m_->unlock();
131 }
132
133private:
134 unique_lock(unique_lock const&); // = delete;
135 unique_lock& operator=(unique_lock const&); // = delete;
136
137public:
Howard Hinnant73d21a42010-09-04 23:28:19 +0000138#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnant333f50d2010-09-21 20:16:37 +0000139 _LIBCPP_INLINE_VISIBILITY
Howard Hinnant499c61f2012-07-21 16:13:09 +0000140 unique_lock(unique_lock&& __u) _NOEXCEPT
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000141 : __m_(__u.__m_), __owns_(__u.__owns_)
142 {__u.__m_ = nullptr; __u.__owns_ = false;}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000143 _LIBCPP_INLINE_VISIBILITY
Howard Hinnant499c61f2012-07-21 16:13:09 +0000144 unique_lock& operator=(unique_lock&& __u) _NOEXCEPT
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000145 {
146 if (__owns_)
147 __m_->unlock();
148 __m_ = __u.__m_;
149 __owns_ = __u.__owns_;
150 __u.__m_ = nullptr;
151 __u.__owns_ = false;
152 return *this;
153 }
Howard Hinnantac417fa2010-11-28 19:41:07 +0000154
Howard Hinnant73d21a42010-09-04 23:28:19 +0000155#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000156
157 void lock();
158 bool try_lock();
159
160 template <class _Rep, class _Period>
161 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
162 template <class _Clock, class _Duration>
163 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
164
165 void unlock();
166
Howard Hinnant333f50d2010-09-21 20:16:37 +0000167 _LIBCPP_INLINE_VISIBILITY
Howard Hinnant499c61f2012-07-21 16:13:09 +0000168 void swap(unique_lock& __u) _NOEXCEPT
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000169 {
Howard Hinnant0949eed2011-06-30 21:18:19 +0000170 _VSTD::swap(__m_, __u.__m_);
171 _VSTD::swap(__owns_, __u.__owns_);
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000172 }
Howard Hinnant333f50d2010-09-21 20:16:37 +0000173 _LIBCPP_INLINE_VISIBILITY
Howard Hinnant499c61f2012-07-21 16:13:09 +0000174 mutex_type* release() _NOEXCEPT
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000175 {
176 mutex_type* __m = __m_;
177 __m_ = nullptr;
178 __owns_ = false;
179 return __m;
180 }
181
Howard Hinnant333f50d2010-09-21 20:16:37 +0000182 _LIBCPP_INLINE_VISIBILITY
Howard Hinnant499c61f2012-07-21 16:13:09 +0000183 bool owns_lock() const _NOEXCEPT {return __owns_;}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000184 _LIBCPP_INLINE_VISIBILITY
Howard Hinnant77861882012-02-21 21:46:43 +0000185 _LIBCPP_EXPLICIT
Howard Hinnant499c61f2012-07-21 16:13:09 +0000186 operator bool () const _NOEXCEPT {return __owns_;}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000187 _LIBCPP_INLINE_VISIBILITY
Howard Hinnant499c61f2012-07-21 16:13:09 +0000188 mutex_type* mutex() const _NOEXCEPT {return __m_;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000189};
190
191template <class _Mutex>
192void
193unique_lock<_Mutex>::lock()
194{
195 if (__m_ == nullptr)
196 __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
197 if (__owns_)
198 __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
199 __m_->lock();
200 __owns_ = true;
201}
202
203template <class _Mutex>
204bool
205unique_lock<_Mutex>::try_lock()
206{
207 if (__m_ == nullptr)
208 __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
209 if (__owns_)
210 __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
211 __owns_ = __m_->try_lock();
212 return __owns_;
213}
214
215template <class _Mutex>
216template <class _Rep, class _Period>
217bool
218unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
219{
220 if (__m_ == nullptr)
221 __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
222 if (__owns_)
223 __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
224 __owns_ = __m_->try_lock_for(__d);
225 return __owns_;
226}
227
228template <class _Mutex>
229template <class _Clock, class _Duration>
230bool
231unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
232{
233 if (__m_ == nullptr)
234 __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
235 if (__owns_)
236 __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
237 __owns_ = __m_->try_lock_until(__t);
238 return __owns_;
239}
240
241template <class _Mutex>
242void
243unique_lock<_Mutex>::unlock()
244{
245 if (!__owns_)
246 __throw_system_error(EPERM, "unique_lock::unlock: not locked");
247 __m_->unlock();
248 __owns_ = false;
249}
250
251template <class _Mutex>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000252inline _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000253void
Howard Hinnant499c61f2012-07-21 16:13:09 +0000254swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT
255 {__x.swap(__y);}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000256
Howard Hinnant83eade62013-03-06 23:30:19 +0000257struct _LIBCPP_TYPE_VIS cv_status
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000258{
Howard Hinnant9c0df142012-10-30 19:06:59 +0000259 enum __lx {
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000260 no_timeout,
261 timeout
262 };
263
Howard Hinnant9c0df142012-10-30 19:06:59 +0000264 __lx __v_;
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000265
Howard Hinnant9c0df142012-10-30 19:06:59 +0000266 _LIBCPP_INLINE_VISIBILITY cv_status(__lx __v) : __v_(__v) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000267 _LIBCPP_INLINE_VISIBILITY operator int() const {return __v_;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000268
269};
270
Howard Hinnant83eade62013-03-06 23:30:19 +0000271class _LIBCPP_TYPE_VIS condition_variable
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000272{
273 pthread_cond_t __cv_;
274public:
Howard Hinnant333f50d2010-09-21 20:16:37 +0000275 _LIBCPP_INLINE_VISIBILITY
Howard Hinnant384608e2012-07-07 20:01:52 +0000276#ifndef _LIBCPP_HAS_NO_CONSTEXPR
Howard Hinnant5c90cba2012-09-11 16:10:20 +0000277 constexpr condition_variable() : __cv_(PTHREAD_COND_INITIALIZER) {}
Howard Hinnant384608e2012-07-07 20:01:52 +0000278#else
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000279 condition_variable() {__cv_ = (pthread_cond_t)PTHREAD_COND_INITIALIZER;}
Howard Hinnant384608e2012-07-07 20:01:52 +0000280#endif
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000281 ~condition_variable();
282
283private:
284 condition_variable(const condition_variable&); // = delete;
285 condition_variable& operator=(const condition_variable&); // = delete;
286
287public:
Howard Hinnantc8f74132012-07-21 16:32:53 +0000288 void notify_one() _NOEXCEPT;
289 void notify_all() _NOEXCEPT;
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000290
291 void wait(unique_lock<mutex>& __lk);
292 template <class _Predicate>
293 void wait(unique_lock<mutex>& __lk, _Predicate __pred);
294
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000295 template <class _Clock, class _Duration>
296 cv_status
297 wait_until(unique_lock<mutex>& __lk,
298 const chrono::time_point<_Clock, _Duration>& __t);
299
300 template <class _Clock, class _Duration, class _Predicate>
301 bool
302 wait_until(unique_lock<mutex>& __lk,
303 const chrono::time_point<_Clock, _Duration>& __t,
304 _Predicate __pred);
305
306 template <class _Rep, class _Period>
307 cv_status
308 wait_for(unique_lock<mutex>& __lk,
309 const chrono::duration<_Rep, _Period>& __d);
310
311 template <class _Rep, class _Period, class _Predicate>
312 bool
313 wait_for(unique_lock<mutex>& __lk,
314 const chrono::duration<_Rep, _Period>& __d,
315 _Predicate __pred);
316
317 typedef pthread_cond_t* native_handle_type;
Howard Hinnant333f50d2010-09-21 20:16:37 +0000318 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000319
320private:
321 void __do_timed_wait(unique_lock<mutex>& __lk,
322 chrono::time_point<chrono::system_clock, chrono::nanoseconds>);
323};
324
325template <class _To, class _Rep, class _Period>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000326inline _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000327typename enable_if
328<
329 chrono::__is_duration<_To>::value,
330 _To
331>::type
332__ceil(chrono::duration<_Rep, _Period> __d)
333{
334 using namespace chrono;
335 _To __r = duration_cast<_To>(__d);
336 if (__r < __d)
337 ++__r;
338 return __r;
339}
340
341template <class _Predicate>
342void
343condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
344{
345 while (!__pred())
346 wait(__lk);
347}
348
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000349template <class _Clock, class _Duration>
350cv_status
351condition_variable::wait_until(unique_lock<mutex>& __lk,
352 const chrono::time_point<_Clock, _Duration>& __t)
353{
354 using namespace chrono;
Howard Hinnantcf115d22012-08-30 19:14:33 +0000355 wait_for(__lk, __t - _Clock::now());
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000356 return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
357}
358
359template <class _Clock, class _Duration, class _Predicate>
360bool
361condition_variable::wait_until(unique_lock<mutex>& __lk,
362 const chrono::time_point<_Clock, _Duration>& __t,
363 _Predicate __pred)
364{
365 while (!__pred())
366 {
367 if (wait_until(__lk, __t) == cv_status::timeout)
368 return __pred();
369 }
370 return true;
371}
372
373template <class _Rep, class _Period>
374cv_status
375condition_variable::wait_for(unique_lock<mutex>& __lk,
376 const chrono::duration<_Rep, _Period>& __d)
377{
378 using namespace chrono;
Howard Hinnantcf115d22012-08-30 19:14:33 +0000379 if (__d <= __d.zero())
380 return cv_status::timeout;
381 typedef time_point<system_clock, duration<long double, nano> > __sys_tpf;
382 typedef time_point<system_clock, nanoseconds> __sys_tpi;
383 __sys_tpf _Max = __sys_tpi::max();
Howard Hinnantf8f85212010-11-20 19:16:30 +0000384 system_clock::time_point __s_now = system_clock::now();
385 steady_clock::time_point __c_now = steady_clock::now();
Howard Hinnantcf115d22012-08-30 19:14:33 +0000386 if (_Max - __d > __s_now)
387 __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d));
388 else
389 __do_timed_wait(__lk, __sys_tpi::max());
Howard Hinnantf8f85212010-11-20 19:16:30 +0000390 return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
391 cv_status::timeout;
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000392}
393
394template <class _Rep, class _Period, class _Predicate>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000395inline _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000396bool
397condition_variable::wait_for(unique_lock<mutex>& __lk,
398 const chrono::duration<_Rep, _Period>& __d,
399 _Predicate __pred)
400{
Howard Hinnantf8f85212010-11-20 19:16:30 +0000401 return wait_until(__lk, chrono::steady_clock::now() + __d,
Howard Hinnant0949eed2011-06-30 21:18:19 +0000402 _VSTD::move(__pred));
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000403}
404
405_LIBCPP_END_NAMESPACE_STD
406
407#endif // _LIBCPP___MUTEX_BASE