blob: d3b2a1be62c9ef246a906d0b69aa2b6843328e2d [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
21_LIBCPP_BEGIN_NAMESPACE_STD
22
Howard Hinnant333f50d2010-09-21 20:16:37 +000023class _LIBCPP_VISIBLE mutex
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000024{
25 pthread_mutex_t __m_;
26
27public:
Howard Hinnant333f50d2010-09-21 20:16:37 +000028 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000029 mutex() {__m_ = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;}
30 ~mutex();
31
32private:
33 mutex(const mutex&);// = delete;
34 mutex& operator=(const mutex&);// = delete;
35
36public:
37 void lock();
38 bool try_lock();
39 void unlock();
40
41 typedef pthread_mutex_t* native_handle_type;
Howard Hinnant333f50d2010-09-21 20:16:37 +000042 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000043};
44
Howard Hinnant333f50d2010-09-21 20:16:37 +000045struct _LIBCPP_VISIBLE defer_lock_t {};
46struct _LIBCPP_VISIBLE try_to_lock_t {};
47struct _LIBCPP_VISIBLE adopt_lock_t {};
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000048
49//constexpr
50extern const
51defer_lock_t defer_lock;
52
53//constexpr
54extern const
55try_to_lock_t try_to_lock;
56
57//constexpr
58extern const
59adopt_lock_t adopt_lock;
60
61template <class _Mutex>
Howard Hinnant333f50d2010-09-21 20:16:37 +000062class _LIBCPP_VISIBLE lock_guard
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000063{
64public:
65 typedef _Mutex mutex_type;
66
67private:
68 mutex_type& __m_;
69public:
70
Howard Hinnant333f50d2010-09-21 20:16:37 +000071 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000072 explicit lock_guard(mutex_type& __m)
73 : __m_(__m) {__m_.lock();}
Howard Hinnant333f50d2010-09-21 20:16:37 +000074 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000075 lock_guard(mutex_type& __m, adopt_lock_t)
76 : __m_(__m) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +000077 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000078 ~lock_guard() {__m_.unlock();}
79
80private:
81 lock_guard(lock_guard const&);// = delete;
82 lock_guard& operator=(lock_guard const&);// = delete;
83};
84
85template <class _Mutex>
Howard Hinnant333f50d2010-09-21 20:16:37 +000086class _LIBCPP_VISIBLE unique_lock
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000087{
88public:
89 typedef _Mutex mutex_type;
90
91private:
92 mutex_type* __m_;
93 bool __owns_;
94
95public:
Howard Hinnant333f50d2010-09-21 20:16:37 +000096 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000097 unique_lock() : __m_(nullptr), __owns_(false) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +000098 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000099 explicit unique_lock(mutex_type& __m)
100 : __m_(&__m), __owns_(true) {__m_->lock();}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000101 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000102 unique_lock(mutex_type& __m, defer_lock_t)
103 : __m_(&__m), __owns_(false) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000104 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000105 unique_lock(mutex_type& __m, try_to_lock_t)
106 : __m_(&__m), __owns_(__m.try_lock()) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000107 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000108 unique_lock(mutex_type& __m, adopt_lock_t)
109 : __m_(&__m), __owns_(true) {}
110 template <class _Clock, class _Duration>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000111 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000112 unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t)
113 : __m_(&__m), __owns_(__m.try_lock_until(__t)) {}
114 template <class _Rep, class _Period>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000115 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000116 unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
117 : __m_(&__m), __owns_(__m.try_lock_for(__d)) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000118 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000119 ~unique_lock()
120 {
121 if (__owns_)
122 __m_->unlock();
123 }
124
125private:
126 unique_lock(unique_lock const&); // = delete;
127 unique_lock& operator=(unique_lock const&); // = delete;
128
129public:
Howard Hinnant73d21a42010-09-04 23:28:19 +0000130#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnant333f50d2010-09-21 20:16:37 +0000131 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000132 unique_lock(unique_lock&& __u)
133 : __m_(__u.__m_), __owns_(__u.__owns_)
134 {__u.__m_ = nullptr; __u.__owns_ = false;}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000135 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000136 unique_lock& operator=(unique_lock&& __u)
137 {
138 if (__owns_)
139 __m_->unlock();
140 __m_ = __u.__m_;
141 __owns_ = __u.__owns_;
142 __u.__m_ = nullptr;
143 __u.__owns_ = false;
144 return *this;
145 }
Howard Hinnant73d21a42010-09-04 23:28:19 +0000146#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000147
148 void lock();
149 bool try_lock();
150
151 template <class _Rep, class _Period>
152 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
153 template <class _Clock, class _Duration>
154 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
155
156 void unlock();
157
Howard Hinnant333f50d2010-09-21 20:16:37 +0000158 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000159 void swap(unique_lock& __u)
160 {
161 _STD::swap(__m_, __u.__m_);
162 _STD::swap(__owns_, __u.__owns_);
163 }
Howard Hinnant333f50d2010-09-21 20:16:37 +0000164 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000165 mutex_type* release()
166 {
167 mutex_type* __m = __m_;
168 __m_ = nullptr;
169 __owns_ = false;
170 return __m;
171 }
172
Howard Hinnant333f50d2010-09-21 20:16:37 +0000173 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000174 bool owns_lock() const {return __owns_;}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000175 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000176// explicit
177 operator bool () const {return __owns_;}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000178 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000179 mutex_type* mutex() const {return __m_;}
180};
181
182template <class _Mutex>
183void
184unique_lock<_Mutex>::lock()
185{
186 if (__m_ == nullptr)
187 __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
188 if (__owns_)
189 __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
190 __m_->lock();
191 __owns_ = true;
192}
193
194template <class _Mutex>
195bool
196unique_lock<_Mutex>::try_lock()
197{
198 if (__m_ == nullptr)
199 __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
200 if (__owns_)
201 __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
202 __owns_ = __m_->try_lock();
203 return __owns_;
204}
205
206template <class _Mutex>
207template <class _Rep, class _Period>
208bool
209unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
210{
211 if (__m_ == nullptr)
212 __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
213 if (__owns_)
214 __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
215 __owns_ = __m_->try_lock_for(__d);
216 return __owns_;
217}
218
219template <class _Mutex>
220template <class _Clock, class _Duration>
221bool
222unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
223{
224 if (__m_ == nullptr)
225 __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
226 if (__owns_)
227 __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
228 __owns_ = __m_->try_lock_until(__t);
229 return __owns_;
230}
231
232template <class _Mutex>
233void
234unique_lock<_Mutex>::unlock()
235{
236 if (!__owns_)
237 __throw_system_error(EPERM, "unique_lock::unlock: not locked");
238 __m_->unlock();
239 __owns_ = false;
240}
241
242template <class _Mutex>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000243inline _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000244void
245swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) {__x.swap(__y);}
246
Howard Hinnant333f50d2010-09-21 20:16:37 +0000247struct _LIBCPP_VISIBLE cv_status
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000248{
249 enum _ {
250 no_timeout,
251 timeout
252 };
253
254 _ __v_;
255
Howard Hinnant333f50d2010-09-21 20:16:37 +0000256 _LIBCPP_INLINE_VISIBILITY cv_status(_ __v) : __v_(__v) {}
257 _LIBCPP_INLINE_VISIBILITY operator int() const {return __v_;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000258
259};
260
Howard Hinnant333f50d2010-09-21 20:16:37 +0000261class _LIBCPP_VISIBLE condition_variable
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000262{
263 pthread_cond_t __cv_;
264public:
Howard Hinnant333f50d2010-09-21 20:16:37 +0000265 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000266 condition_variable() {__cv_ = (pthread_cond_t)PTHREAD_COND_INITIALIZER;}
267 ~condition_variable();
268
269private:
270 condition_variable(const condition_variable&); // = delete;
271 condition_variable& operator=(const condition_variable&); // = delete;
272
273public:
274 void notify_one();
275 void notify_all();
276
277 void wait(unique_lock<mutex>& __lk);
278 template <class _Predicate>
279 void wait(unique_lock<mutex>& __lk, _Predicate __pred);
280
281 template <class _Duration>
282 cv_status
283 wait_until(unique_lock<mutex>& __lk,
284 const chrono::time_point<chrono::system_clock, _Duration>& __t);
285
286 template <class _Clock, class _Duration>
287 cv_status
288 wait_until(unique_lock<mutex>& __lk,
289 const chrono::time_point<_Clock, _Duration>& __t);
290
291 template <class _Clock, class _Duration, class _Predicate>
292 bool
293 wait_until(unique_lock<mutex>& __lk,
294 const chrono::time_point<_Clock, _Duration>& __t,
295 _Predicate __pred);
296
297 template <class _Rep, class _Period>
298 cv_status
299 wait_for(unique_lock<mutex>& __lk,
300 const chrono::duration<_Rep, _Period>& __d);
301
302 template <class _Rep, class _Period, class _Predicate>
303 bool
304 wait_for(unique_lock<mutex>& __lk,
305 const chrono::duration<_Rep, _Period>& __d,
306 _Predicate __pred);
307
308 typedef pthread_cond_t* native_handle_type;
Howard Hinnant333f50d2010-09-21 20:16:37 +0000309 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000310
311private:
312 void __do_timed_wait(unique_lock<mutex>& __lk,
313 chrono::time_point<chrono::system_clock, chrono::nanoseconds>);
314};
315
316template <class _To, class _Rep, class _Period>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000317inline _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000318typename enable_if
319<
320 chrono::__is_duration<_To>::value,
321 _To
322>::type
323__ceil(chrono::duration<_Rep, _Period> __d)
324{
325 using namespace chrono;
326 _To __r = duration_cast<_To>(__d);
327 if (__r < __d)
328 ++__r;
329 return __r;
330}
331
332template <class _Predicate>
333void
334condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
335{
336 while (!__pred())
337 wait(__lk);
338}
339
340template <class _Duration>
341cv_status
342condition_variable::wait_until(unique_lock<mutex>& __lk,
343 const chrono::time_point<chrono::system_clock, _Duration>& __t)
344{
345 using namespace chrono;
346 typedef time_point<system_clock, nanoseconds> __nano_sys_tmpt;
347 __do_timed_wait(__lk,
348 __nano_sys_tmpt(__ceil<nanoseconds>(__t.time_since_epoch())));
349 return system_clock::now() < __t ? cv_status::no_timeout :
350 cv_status::timeout;
351}
352
353template <class _Clock, class _Duration>
354cv_status
355condition_variable::wait_until(unique_lock<mutex>& __lk,
356 const chrono::time_point<_Clock, _Duration>& __t)
357{
358 using namespace chrono;
359 system_clock::time_point __s_now = system_clock::now();
360 typename _Clock::time_point __c_now = _Clock::now();
361 __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__t - __c_now));
362 return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
363}
364
365template <class _Clock, class _Duration, class _Predicate>
366bool
367condition_variable::wait_until(unique_lock<mutex>& __lk,
368 const chrono::time_point<_Clock, _Duration>& __t,
369 _Predicate __pred)
370{
371 while (!__pred())
372 {
373 if (wait_until(__lk, __t) == cv_status::timeout)
374 return __pred();
375 }
376 return true;
377}
378
379template <class _Rep, class _Period>
380cv_status
381condition_variable::wait_for(unique_lock<mutex>& __lk,
382 const chrono::duration<_Rep, _Period>& __d)
383{
384 using namespace chrono;
Howard Hinnantf8f85212010-11-20 19:16:30 +0000385 system_clock::time_point __s_now = system_clock::now();
386 steady_clock::time_point __c_now = steady_clock::now();
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000387 __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d));
Howard Hinnantf8f85212010-11-20 19:16:30 +0000388 return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
389 cv_status::timeout;
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000390}
391
392template <class _Rep, class _Period, class _Predicate>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000393inline _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000394bool
395condition_variable::wait_for(unique_lock<mutex>& __lk,
396 const chrono::duration<_Rep, _Period>& __d,
397 _Predicate __pred)
398{
Howard Hinnantf8f85212010-11-20 19:16:30 +0000399 return wait_until(__lk, chrono::steady_clock::now() + __d,
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000400 _STD::move(__pred));
401}
402
403_LIBCPP_END_NAMESPACE_STD
404
405#endif // _LIBCPP___MUTEX_BASE