blob: 9e472fcc267a05beab84fb7d24c2055a58c1ec74 [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
19#pragma GCC system_header
20
Howard Hinnantac417fa2010-11-28 19:41:07 +000021#ifdef _LIBCPP_SHARED_LOCK
22
23namespace ting {
Howard Hinnant2b1b2d42011-06-14 19:58:17 +000024template <class _Mutex> class shared_lock;
25template <class _Mutex> class upgrade_lock;
Howard Hinnantac417fa2010-11-28 19:41:07 +000026}
27
28#endif // _LIBCPP_SHARED_LOCK
29
30
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000031_LIBCPP_BEGIN_NAMESPACE_STD
32
Howard Hinnant333f50d2010-09-21 20:16:37 +000033class _LIBCPP_VISIBLE mutex
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000034{
35 pthread_mutex_t __m_;
36
37public:
Howard Hinnant333f50d2010-09-21 20:16:37 +000038 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000039 mutex() {__m_ = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;}
40 ~mutex();
41
42private:
43 mutex(const mutex&);// = delete;
44 mutex& operator=(const mutex&);// = delete;
45
46public:
47 void lock();
48 bool try_lock();
49 void unlock();
50
51 typedef pthread_mutex_t* native_handle_type;
Howard Hinnant333f50d2010-09-21 20:16:37 +000052 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000053};
54
Howard Hinnant333f50d2010-09-21 20:16:37 +000055struct _LIBCPP_VISIBLE defer_lock_t {};
56struct _LIBCPP_VISIBLE try_to_lock_t {};
57struct _LIBCPP_VISIBLE adopt_lock_t {};
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000058
59//constexpr
60extern const
61defer_lock_t defer_lock;
62
63//constexpr
64extern const
65try_to_lock_t try_to_lock;
66
67//constexpr
68extern const
69adopt_lock_t adopt_lock;
70
71template <class _Mutex>
Howard Hinnant333f50d2010-09-21 20:16:37 +000072class _LIBCPP_VISIBLE lock_guard
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000073{
74public:
75 typedef _Mutex mutex_type;
76
77private:
78 mutex_type& __m_;
79public:
80
Howard Hinnant333f50d2010-09-21 20:16:37 +000081 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000082 explicit lock_guard(mutex_type& __m)
83 : __m_(__m) {__m_.lock();}
Howard Hinnant333f50d2010-09-21 20:16:37 +000084 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000085 lock_guard(mutex_type& __m, adopt_lock_t)
86 : __m_(__m) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +000087 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000088 ~lock_guard() {__m_.unlock();}
89
90private:
91 lock_guard(lock_guard const&);// = delete;
92 lock_guard& operator=(lock_guard const&);// = delete;
93};
94
95template <class _Mutex>
Howard Hinnant333f50d2010-09-21 20:16:37 +000096class _LIBCPP_VISIBLE unique_lock
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000097{
98public:
99 typedef _Mutex mutex_type;
100
101private:
102 mutex_type* __m_;
103 bool __owns_;
104
105public:
Howard Hinnant333f50d2010-09-21 20:16:37 +0000106 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000107 unique_lock() : __m_(nullptr), __owns_(false) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000108 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000109 explicit unique_lock(mutex_type& __m)
110 : __m_(&__m), __owns_(true) {__m_->lock();}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000111 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000112 unique_lock(mutex_type& __m, defer_lock_t)
113 : __m_(&__m), __owns_(false) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000114 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000115 unique_lock(mutex_type& __m, try_to_lock_t)
116 : __m_(&__m), __owns_(__m.try_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, adopt_lock_t)
119 : __m_(&__m), __owns_(true) {}
120 template <class _Clock, class _Duration>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000121 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000122 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>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000125 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000126 unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
127 : __m_(&__m), __owns_(__m.try_lock_for(__d)) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000128 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000129 ~unique_lock()
130 {
131 if (__owns_)
132 __m_->unlock();
133 }
134
135private:
136 unique_lock(unique_lock const&); // = delete;
137 unique_lock& operator=(unique_lock const&); // = delete;
138
139public:
Howard Hinnant73d21a42010-09-04 23:28:19 +0000140#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnant333f50d2010-09-21 20:16:37 +0000141 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000142 unique_lock(unique_lock&& __u)
143 : __m_(__u.__m_), __owns_(__u.__owns_)
144 {__u.__m_ = nullptr; __u.__owns_ = false;}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000145 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000146 unique_lock& operator=(unique_lock&& __u)
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 }
Howard Hinnantac417fa2010-11-28 19:41:07 +0000156
157#ifdef _LIBCPP_SHARED_LOCK
158
159 unique_lock(ting::shared_lock<mutex_type>&&, try_to_lock_t);
160 template <class _Clock, class _Duration>
161 unique_lock(ting::shared_lock<mutex_type>&&,
162 const chrono::time_point<_Clock, _Duration>&);
163 template <class _Rep, class _Period>
164 unique_lock(ting::shared_lock<mutex_type>&&,
165 const chrono::duration<_Rep, _Period>&);
166
167 explicit unique_lock(ting::upgrade_lock<mutex_type>&&);
168 unique_lock(ting::upgrade_lock<mutex_type>&&, try_to_lock_t);
169 template <class _Clock, class _Duration>
170 unique_lock(ting::upgrade_lock<mutex_type>&&,
171 const chrono::time_point<_Clock, _Duration>&);
172 template <class _Rep, class _Period>
173 unique_lock(ting::upgrade_lock<mutex_type>&&,
174 const chrono::duration<_Rep, _Period>&);
175
176#endif // _LIBCPP_SHARED_LOCK
177
Howard Hinnant73d21a42010-09-04 23:28:19 +0000178#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000179
180 void lock();
181 bool try_lock();
182
183 template <class _Rep, class _Period>
184 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
185 template <class _Clock, class _Duration>
186 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
187
188 void unlock();
189
Howard Hinnant333f50d2010-09-21 20:16:37 +0000190 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000191 void swap(unique_lock& __u)
192 {
Howard Hinnant0949eed2011-06-30 21:18:19 +0000193 _VSTD::swap(__m_, __u.__m_);
194 _VSTD::swap(__owns_, __u.__owns_);
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000195 }
Howard Hinnant333f50d2010-09-21 20:16:37 +0000196 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000197 mutex_type* release()
198 {
199 mutex_type* __m = __m_;
200 __m_ = nullptr;
201 __owns_ = false;
202 return __m;
203 }
204
Howard Hinnant333f50d2010-09-21 20:16:37 +0000205 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000206 bool owns_lock() const {return __owns_;}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000207 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000208// explicit
209 operator bool () const {return __owns_;}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000210 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000211 mutex_type* mutex() const {return __m_;}
212};
213
214template <class _Mutex>
215void
216unique_lock<_Mutex>::lock()
217{
218 if (__m_ == nullptr)
219 __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
220 if (__owns_)
221 __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
222 __m_->lock();
223 __owns_ = true;
224}
225
226template <class _Mutex>
227bool
228unique_lock<_Mutex>::try_lock()
229{
230 if (__m_ == nullptr)
231 __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
232 if (__owns_)
233 __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
234 __owns_ = __m_->try_lock();
235 return __owns_;
236}
237
238template <class _Mutex>
239template <class _Rep, class _Period>
240bool
241unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
242{
243 if (__m_ == nullptr)
244 __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
245 if (__owns_)
246 __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
247 __owns_ = __m_->try_lock_for(__d);
248 return __owns_;
249}
250
251template <class _Mutex>
252template <class _Clock, class _Duration>
253bool
254unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
255{
256 if (__m_ == nullptr)
257 __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
258 if (__owns_)
259 __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
260 __owns_ = __m_->try_lock_until(__t);
261 return __owns_;
262}
263
264template <class _Mutex>
265void
266unique_lock<_Mutex>::unlock()
267{
268 if (!__owns_)
269 __throw_system_error(EPERM, "unique_lock::unlock: not locked");
270 __m_->unlock();
271 __owns_ = false;
272}
273
274template <class _Mutex>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000275inline _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000276void
277swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) {__x.swap(__y);}
278
Howard Hinnant333f50d2010-09-21 20:16:37 +0000279struct _LIBCPP_VISIBLE cv_status
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000280{
281 enum _ {
282 no_timeout,
283 timeout
284 };
285
286 _ __v_;
287
Howard Hinnant333f50d2010-09-21 20:16:37 +0000288 _LIBCPP_INLINE_VISIBILITY cv_status(_ __v) : __v_(__v) {}
289 _LIBCPP_INLINE_VISIBILITY operator int() const {return __v_;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000290
291};
292
Howard Hinnant333f50d2010-09-21 20:16:37 +0000293class _LIBCPP_VISIBLE condition_variable
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000294{
295 pthread_cond_t __cv_;
296public:
Howard Hinnant333f50d2010-09-21 20:16:37 +0000297 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000298 condition_variable() {__cv_ = (pthread_cond_t)PTHREAD_COND_INITIALIZER;}
299 ~condition_variable();
300
301private:
302 condition_variable(const condition_variable&); // = delete;
303 condition_variable& operator=(const condition_variable&); // = delete;
304
305public:
306 void notify_one();
307 void notify_all();
308
309 void wait(unique_lock<mutex>& __lk);
310 template <class _Predicate>
311 void wait(unique_lock<mutex>& __lk, _Predicate __pred);
312
313 template <class _Duration>
314 cv_status
315 wait_until(unique_lock<mutex>& __lk,
316 const chrono::time_point<chrono::system_clock, _Duration>& __t);
317
318 template <class _Clock, class _Duration>
319 cv_status
320 wait_until(unique_lock<mutex>& __lk,
321 const chrono::time_point<_Clock, _Duration>& __t);
322
323 template <class _Clock, class _Duration, class _Predicate>
324 bool
325 wait_until(unique_lock<mutex>& __lk,
326 const chrono::time_point<_Clock, _Duration>& __t,
327 _Predicate __pred);
328
329 template <class _Rep, class _Period>
330 cv_status
331 wait_for(unique_lock<mutex>& __lk,
332 const chrono::duration<_Rep, _Period>& __d);
333
334 template <class _Rep, class _Period, class _Predicate>
335 bool
336 wait_for(unique_lock<mutex>& __lk,
337 const chrono::duration<_Rep, _Period>& __d,
338 _Predicate __pred);
339
340 typedef pthread_cond_t* native_handle_type;
Howard Hinnant333f50d2010-09-21 20:16:37 +0000341 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000342
343private:
344 void __do_timed_wait(unique_lock<mutex>& __lk,
345 chrono::time_point<chrono::system_clock, chrono::nanoseconds>);
346};
347
348template <class _To, class _Rep, class _Period>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000349inline _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000350typename enable_if
351<
352 chrono::__is_duration<_To>::value,
353 _To
354>::type
355__ceil(chrono::duration<_Rep, _Period> __d)
356{
357 using namespace chrono;
358 _To __r = duration_cast<_To>(__d);
359 if (__r < __d)
360 ++__r;
361 return __r;
362}
363
364template <class _Predicate>
365void
366condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
367{
368 while (!__pred())
369 wait(__lk);
370}
371
372template <class _Duration>
373cv_status
374condition_variable::wait_until(unique_lock<mutex>& __lk,
375 const chrono::time_point<chrono::system_clock, _Duration>& __t)
376{
377 using namespace chrono;
378 typedef time_point<system_clock, nanoseconds> __nano_sys_tmpt;
379 __do_timed_wait(__lk,
380 __nano_sys_tmpt(__ceil<nanoseconds>(__t.time_since_epoch())));
381 return system_clock::now() < __t ? cv_status::no_timeout :
382 cv_status::timeout;
383}
384
385template <class _Clock, class _Duration>
386cv_status
387condition_variable::wait_until(unique_lock<mutex>& __lk,
388 const chrono::time_point<_Clock, _Duration>& __t)
389{
390 using namespace chrono;
391 system_clock::time_point __s_now = system_clock::now();
392 typename _Clock::time_point __c_now = _Clock::now();
393 __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__t - __c_now));
394 return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
395}
396
397template <class _Clock, class _Duration, class _Predicate>
398bool
399condition_variable::wait_until(unique_lock<mutex>& __lk,
400 const chrono::time_point<_Clock, _Duration>& __t,
401 _Predicate __pred)
402{
403 while (!__pred())
404 {
405 if (wait_until(__lk, __t) == cv_status::timeout)
406 return __pred();
407 }
408 return true;
409}
410
411template <class _Rep, class _Period>
412cv_status
413condition_variable::wait_for(unique_lock<mutex>& __lk,
414 const chrono::duration<_Rep, _Period>& __d)
415{
416 using namespace chrono;
Howard Hinnantf8f85212010-11-20 19:16:30 +0000417 system_clock::time_point __s_now = system_clock::now();
418 steady_clock::time_point __c_now = steady_clock::now();
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000419 __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d));
Howard Hinnantf8f85212010-11-20 19:16:30 +0000420 return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
421 cv_status::timeout;
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000422}
423
424template <class _Rep, class _Period, class _Predicate>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000425inline _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000426bool
427condition_variable::wait_for(unique_lock<mutex>& __lk,
428 const chrono::duration<_Rep, _Period>& __d,
429 _Predicate __pred)
430{
Howard Hinnantf8f85212010-11-20 19:16:30 +0000431 return wait_until(__lk, chrono::steady_clock::now() + __d,
Howard Hinnant0949eed2011-06-30 21:18:19 +0000432 _VSTD::move(__pred));
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000433}
434
435_LIBCPP_END_NAMESPACE_STD
436
437#endif // _LIBCPP___MUTEX_BASE