blob: 854f02c436f911e71aecae5a459bc9a0d4cdc8f3 [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
Howard Hinnantac417fa2010-11-28 19:41:07 +000023#ifdef _LIBCPP_SHARED_LOCK
24
25namespace ting {
Howard Hinnant2b1b2d42011-06-14 19:58:17 +000026template <class _Mutex> class shared_lock;
27template <class _Mutex> class upgrade_lock;
Howard Hinnantac417fa2010-11-28 19:41:07 +000028}
29
30#endif // _LIBCPP_SHARED_LOCK
31
32
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000033_LIBCPP_BEGIN_NAMESPACE_STD
34
Howard Hinnant333f50d2010-09-21 20:16:37 +000035class _LIBCPP_VISIBLE mutex
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000036{
37 pthread_mutex_t __m_;
38
39public:
Howard Hinnant333f50d2010-09-21 20:16:37 +000040 _LIBCPP_INLINE_VISIBILITY
Howard Hinnant384608e2012-07-07 20:01:52 +000041#ifndef _LIBCPP_HAS_NO_CONSTEXPR
42 constexpr mutex() : __m_ PTHREAD_MUTEX_INITIALIZER {}
43#else
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000044 mutex() {__m_ = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;}
Howard Hinnant384608e2012-07-07 20:01:52 +000045#endif
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000046 ~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;
Howard Hinnant333f50d2010-09-21 20:16:37 +000058 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000059};
60
Howard Hinnant333f50d2010-09-21 20:16:37 +000061struct _LIBCPP_VISIBLE defer_lock_t {};
62struct _LIBCPP_VISIBLE try_to_lock_t {};
63struct _LIBCPP_VISIBLE adopt_lock_t {};
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000064
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>
Howard Hinnant333f50d2010-09-21 20:16:37 +000078class _LIBCPP_VISIBLE lock_guard
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000079{
80public:
81 typedef _Mutex mutex_type;
82
83private:
84 mutex_type& __m_;
85public:
86
Howard Hinnant333f50d2010-09-21 20:16:37 +000087 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000088 explicit lock_guard(mutex_type& __m)
89 : __m_(__m) {__m_.lock();}
Howard Hinnant333f50d2010-09-21 20:16:37 +000090 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000091 lock_guard(mutex_type& __m, adopt_lock_t)
92 : __m_(__m) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +000093 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000094 ~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>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000102class _LIBCPP_VISIBLE unique_lock
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000103{
104public:
105 typedef _Mutex mutex_type;
106
107private:
108 mutex_type* __m_;
109 bool __owns_;
110
111public:
Howard Hinnant333f50d2010-09-21 20:16:37 +0000112 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000113 unique_lock() : __m_(nullptr), __owns_(false) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000114 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000115 explicit unique_lock(mutex_type& __m)
116 : __m_(&__m), __owns_(true) {__m_->lock();}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000117 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000118 unique_lock(mutex_type& __m, defer_lock_t)
119 : __m_(&__m), __owns_(false) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000120 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000121 unique_lock(mutex_type& __m, try_to_lock_t)
122 : __m_(&__m), __owns_(__m.try_lock()) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000123 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000124 unique_lock(mutex_type& __m, adopt_lock_t)
125 : __m_(&__m), __owns_(true) {}
126 template <class _Clock, class _Duration>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000127 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000128 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>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000131 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000132 unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
133 : __m_(&__m), __owns_(__m.try_lock_for(__d)) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000134 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000135 ~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:
Howard Hinnant73d21a42010-09-04 23:28:19 +0000146#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnant333f50d2010-09-21 20:16:37 +0000147 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000148 unique_lock(unique_lock&& __u)
149 : __m_(__u.__m_), __owns_(__u.__owns_)
150 {__u.__m_ = nullptr; __u.__owns_ = false;}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000151 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000152 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 }
Howard Hinnantac417fa2010-11-28 19:41:07 +0000162
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
Howard Hinnant73d21a42010-09-04 23:28:19 +0000184#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000185
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
Howard Hinnant333f50d2010-09-21 20:16:37 +0000196 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000197 void swap(unique_lock& __u)
198 {
Howard Hinnant0949eed2011-06-30 21:18:19 +0000199 _VSTD::swap(__m_, __u.__m_);
200 _VSTD::swap(__owns_, __u.__owns_);
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000201 }
Howard Hinnant333f50d2010-09-21 20:16:37 +0000202 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000203 mutex_type* release()
204 {
205 mutex_type* __m = __m_;
206 __m_ = nullptr;
207 __owns_ = false;
208 return __m;
209 }
210
Howard Hinnant333f50d2010-09-21 20:16:37 +0000211 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000212 bool owns_lock() const {return __owns_;}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000213 _LIBCPP_INLINE_VISIBILITY
Howard Hinnant77861882012-02-21 21:46:43 +0000214 _LIBCPP_EXPLICIT
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000215 operator bool () const {return __owns_;}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000216 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000217 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>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000281inline _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000282void
283swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) {__x.swap(__y);}
284
Howard Hinnant333f50d2010-09-21 20:16:37 +0000285struct _LIBCPP_VISIBLE cv_status
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000286{
287 enum _ {
288 no_timeout,
289 timeout
290 };
291
292 _ __v_;
293
Howard Hinnant333f50d2010-09-21 20:16:37 +0000294 _LIBCPP_INLINE_VISIBILITY cv_status(_ __v) : __v_(__v) {}
295 _LIBCPP_INLINE_VISIBILITY operator int() const {return __v_;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000296
297};
298
Howard Hinnant333f50d2010-09-21 20:16:37 +0000299class _LIBCPP_VISIBLE condition_variable
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000300{
301 pthread_cond_t __cv_;
302public:
Howard Hinnant333f50d2010-09-21 20:16:37 +0000303 _LIBCPP_INLINE_VISIBILITY
Howard Hinnant384608e2012-07-07 20:01:52 +0000304#ifndef _LIBCPP_HAS_NO_CONSTEXPR
305 constexpr condition_variable() : __cv_ PTHREAD_COND_INITIALIZER {}
306#else
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000307 condition_variable() {__cv_ = (pthread_cond_t)PTHREAD_COND_INITIALIZER;}
Howard Hinnant384608e2012-07-07 20:01:52 +0000308#endif
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000309 ~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;
Howard Hinnant333f50d2010-09-21 20:16:37 +0000351 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000352
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>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000359inline _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000360typename 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;
Howard Hinnantf8f85212010-11-20 19:16:30 +0000427 system_clock::time_point __s_now = system_clock::now();
428 steady_clock::time_point __c_now = steady_clock::now();
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000429 __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d));
Howard Hinnantf8f85212010-11-20 19:16:30 +0000430 return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
431 cv_status::timeout;
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000432}
433
434template <class _Rep, class _Period, class _Predicate>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000435inline _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000436bool
437condition_variable::wait_for(unique_lock<mutex>& __lk,
438 const chrono::duration<_Rep, _Period>& __d,
439 _Predicate __pred)
440{
Howard Hinnantf8f85212010-11-20 19:16:30 +0000441 return wait_until(__lk, chrono::steady_clock::now() + __d,
Howard Hinnant0949eed2011-06-30 21:18:19 +0000442 _VSTD::move(__pred));
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000443}
444
445_LIBCPP_END_NAMESPACE_STD
446
447#endif // _LIBCPP___MUTEX_BASE