blob: 55687659a03a738e9e261800b4810c728c177c0d [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 Hinnantbc8d3f92010-05-11 19:42:16 +000041 mutex() {__m_ = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;}
42 ~mutex();
43
44private:
45 mutex(const mutex&);// = delete;
46 mutex& operator=(const mutex&);// = delete;
47
48public:
49 void lock();
50 bool try_lock();
51 void unlock();
52
53 typedef pthread_mutex_t* native_handle_type;
Howard Hinnant333f50d2010-09-21 20:16:37 +000054 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000055};
56
Howard Hinnant333f50d2010-09-21 20:16:37 +000057struct _LIBCPP_VISIBLE defer_lock_t {};
58struct _LIBCPP_VISIBLE try_to_lock_t {};
59struct _LIBCPP_VISIBLE adopt_lock_t {};
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000060
61//constexpr
62extern const
63defer_lock_t defer_lock;
64
65//constexpr
66extern const
67try_to_lock_t try_to_lock;
68
69//constexpr
70extern const
71adopt_lock_t adopt_lock;
72
73template <class _Mutex>
Howard Hinnant333f50d2010-09-21 20:16:37 +000074class _LIBCPP_VISIBLE lock_guard
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000075{
76public:
77 typedef _Mutex mutex_type;
78
79private:
80 mutex_type& __m_;
81public:
82
Howard Hinnant333f50d2010-09-21 20:16:37 +000083 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000084 explicit lock_guard(mutex_type& __m)
85 : __m_(__m) {__m_.lock();}
Howard Hinnant333f50d2010-09-21 20:16:37 +000086 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000087 lock_guard(mutex_type& __m, adopt_lock_t)
88 : __m_(__m) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +000089 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000090 ~lock_guard() {__m_.unlock();}
91
92private:
93 lock_guard(lock_guard const&);// = delete;
94 lock_guard& operator=(lock_guard const&);// = delete;
95};
96
97template <class _Mutex>
Howard Hinnant333f50d2010-09-21 20:16:37 +000098class _LIBCPP_VISIBLE unique_lock
Howard Hinnantbc8d3f92010-05-11 19:42:16 +000099{
100public:
101 typedef _Mutex mutex_type;
102
103private:
104 mutex_type* __m_;
105 bool __owns_;
106
107public:
Howard Hinnant333f50d2010-09-21 20:16:37 +0000108 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000109 unique_lock() : __m_(nullptr), __owns_(false) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000110 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000111 explicit unique_lock(mutex_type& __m)
112 : __m_(&__m), __owns_(true) {__m_->lock();}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000113 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000114 unique_lock(mutex_type& __m, defer_lock_t)
115 : __m_(&__m), __owns_(false) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000116 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000117 unique_lock(mutex_type& __m, try_to_lock_t)
118 : __m_(&__m), __owns_(__m.try_lock()) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000119 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000120 unique_lock(mutex_type& __m, adopt_lock_t)
121 : __m_(&__m), __owns_(true) {}
122 template <class _Clock, class _Duration>
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::time_point<_Clock, _Duration>& __t)
125 : __m_(&__m), __owns_(__m.try_lock_until(__t)) {}
126 template <class _Rep, class _Period>
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::duration<_Rep, _Period>& __d)
129 : __m_(&__m), __owns_(__m.try_lock_for(__d)) {}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000130 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000131 ~unique_lock()
132 {
133 if (__owns_)
134 __m_->unlock();
135 }
136
137private:
138 unique_lock(unique_lock const&); // = delete;
139 unique_lock& operator=(unique_lock const&); // = delete;
140
141public:
Howard Hinnant73d21a42010-09-04 23:28:19 +0000142#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnant333f50d2010-09-21 20:16:37 +0000143 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000144 unique_lock(unique_lock&& __u)
145 : __m_(__u.__m_), __owns_(__u.__owns_)
146 {__u.__m_ = nullptr; __u.__owns_ = false;}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000147 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000148 unique_lock& operator=(unique_lock&& __u)
149 {
150 if (__owns_)
151 __m_->unlock();
152 __m_ = __u.__m_;
153 __owns_ = __u.__owns_;
154 __u.__m_ = nullptr;
155 __u.__owns_ = false;
156 return *this;
157 }
Howard Hinnantac417fa2010-11-28 19:41:07 +0000158
159#ifdef _LIBCPP_SHARED_LOCK
160
161 unique_lock(ting::shared_lock<mutex_type>&&, try_to_lock_t);
162 template <class _Clock, class _Duration>
163 unique_lock(ting::shared_lock<mutex_type>&&,
164 const chrono::time_point<_Clock, _Duration>&);
165 template <class _Rep, class _Period>
166 unique_lock(ting::shared_lock<mutex_type>&&,
167 const chrono::duration<_Rep, _Period>&);
168
169 explicit unique_lock(ting::upgrade_lock<mutex_type>&&);
170 unique_lock(ting::upgrade_lock<mutex_type>&&, try_to_lock_t);
171 template <class _Clock, class _Duration>
172 unique_lock(ting::upgrade_lock<mutex_type>&&,
173 const chrono::time_point<_Clock, _Duration>&);
174 template <class _Rep, class _Period>
175 unique_lock(ting::upgrade_lock<mutex_type>&&,
176 const chrono::duration<_Rep, _Period>&);
177
178#endif // _LIBCPP_SHARED_LOCK
179
Howard Hinnant73d21a42010-09-04 23:28:19 +0000180#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000181
182 void lock();
183 bool try_lock();
184
185 template <class _Rep, class _Period>
186 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
187 template <class _Clock, class _Duration>
188 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
189
190 void unlock();
191
Howard Hinnant333f50d2010-09-21 20:16:37 +0000192 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000193 void swap(unique_lock& __u)
194 {
Howard Hinnant0949eed2011-06-30 21:18:19 +0000195 _VSTD::swap(__m_, __u.__m_);
196 _VSTD::swap(__owns_, __u.__owns_);
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000197 }
Howard Hinnant333f50d2010-09-21 20:16:37 +0000198 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000199 mutex_type* release()
200 {
201 mutex_type* __m = __m_;
202 __m_ = nullptr;
203 __owns_ = false;
204 return __m;
205 }
206
Howard Hinnant333f50d2010-09-21 20:16:37 +0000207 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000208 bool owns_lock() const {return __owns_;}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000209 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000210// explicit
211 operator bool () const {return __owns_;}
Howard Hinnant333f50d2010-09-21 20:16:37 +0000212 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000213 mutex_type* mutex() const {return __m_;}
214};
215
216template <class _Mutex>
217void
218unique_lock<_Mutex>::lock()
219{
220 if (__m_ == nullptr)
221 __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
222 if (__owns_)
223 __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
224 __m_->lock();
225 __owns_ = true;
226}
227
228template <class _Mutex>
229bool
230unique_lock<_Mutex>::try_lock()
231{
232 if (__m_ == nullptr)
233 __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
234 if (__owns_)
235 __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
236 __owns_ = __m_->try_lock();
237 return __owns_;
238}
239
240template <class _Mutex>
241template <class _Rep, class _Period>
242bool
243unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
244{
245 if (__m_ == nullptr)
246 __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
247 if (__owns_)
248 __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
249 __owns_ = __m_->try_lock_for(__d);
250 return __owns_;
251}
252
253template <class _Mutex>
254template <class _Clock, class _Duration>
255bool
256unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
257{
258 if (__m_ == nullptr)
259 __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
260 if (__owns_)
261 __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
262 __owns_ = __m_->try_lock_until(__t);
263 return __owns_;
264}
265
266template <class _Mutex>
267void
268unique_lock<_Mutex>::unlock()
269{
270 if (!__owns_)
271 __throw_system_error(EPERM, "unique_lock::unlock: not locked");
272 __m_->unlock();
273 __owns_ = false;
274}
275
276template <class _Mutex>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000277inline _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000278void
279swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) {__x.swap(__y);}
280
Howard Hinnant333f50d2010-09-21 20:16:37 +0000281struct _LIBCPP_VISIBLE cv_status
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000282{
283 enum _ {
284 no_timeout,
285 timeout
286 };
287
288 _ __v_;
289
Howard Hinnant333f50d2010-09-21 20:16:37 +0000290 _LIBCPP_INLINE_VISIBILITY cv_status(_ __v) : __v_(__v) {}
291 _LIBCPP_INLINE_VISIBILITY operator int() const {return __v_;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000292
293};
294
Howard Hinnant333f50d2010-09-21 20:16:37 +0000295class _LIBCPP_VISIBLE condition_variable
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000296{
297 pthread_cond_t __cv_;
298public:
Howard Hinnant333f50d2010-09-21 20:16:37 +0000299 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000300 condition_variable() {__cv_ = (pthread_cond_t)PTHREAD_COND_INITIALIZER;}
301 ~condition_variable();
302
303private:
304 condition_variable(const condition_variable&); // = delete;
305 condition_variable& operator=(const condition_variable&); // = delete;
306
307public:
308 void notify_one();
309 void notify_all();
310
311 void wait(unique_lock<mutex>& __lk);
312 template <class _Predicate>
313 void wait(unique_lock<mutex>& __lk, _Predicate __pred);
314
315 template <class _Duration>
316 cv_status
317 wait_until(unique_lock<mutex>& __lk,
318 const chrono::time_point<chrono::system_clock, _Duration>& __t);
319
320 template <class _Clock, class _Duration>
321 cv_status
322 wait_until(unique_lock<mutex>& __lk,
323 const chrono::time_point<_Clock, _Duration>& __t);
324
325 template <class _Clock, class _Duration, class _Predicate>
326 bool
327 wait_until(unique_lock<mutex>& __lk,
328 const chrono::time_point<_Clock, _Duration>& __t,
329 _Predicate __pred);
330
331 template <class _Rep, class _Period>
332 cv_status
333 wait_for(unique_lock<mutex>& __lk,
334 const chrono::duration<_Rep, _Period>& __d);
335
336 template <class _Rep, class _Period, class _Predicate>
337 bool
338 wait_for(unique_lock<mutex>& __lk,
339 const chrono::duration<_Rep, _Period>& __d,
340 _Predicate __pred);
341
342 typedef pthread_cond_t* native_handle_type;
Howard Hinnant333f50d2010-09-21 20:16:37 +0000343 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000344
345private:
346 void __do_timed_wait(unique_lock<mutex>& __lk,
347 chrono::time_point<chrono::system_clock, chrono::nanoseconds>);
348};
349
350template <class _To, class _Rep, class _Period>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000351inline _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000352typename enable_if
353<
354 chrono::__is_duration<_To>::value,
355 _To
356>::type
357__ceil(chrono::duration<_Rep, _Period> __d)
358{
359 using namespace chrono;
360 _To __r = duration_cast<_To>(__d);
361 if (__r < __d)
362 ++__r;
363 return __r;
364}
365
366template <class _Predicate>
367void
368condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
369{
370 while (!__pred())
371 wait(__lk);
372}
373
374template <class _Duration>
375cv_status
376condition_variable::wait_until(unique_lock<mutex>& __lk,
377 const chrono::time_point<chrono::system_clock, _Duration>& __t)
378{
379 using namespace chrono;
380 typedef time_point<system_clock, nanoseconds> __nano_sys_tmpt;
381 __do_timed_wait(__lk,
382 __nano_sys_tmpt(__ceil<nanoseconds>(__t.time_since_epoch())));
383 return system_clock::now() < __t ? cv_status::no_timeout :
384 cv_status::timeout;
385}
386
387template <class _Clock, class _Duration>
388cv_status
389condition_variable::wait_until(unique_lock<mutex>& __lk,
390 const chrono::time_point<_Clock, _Duration>& __t)
391{
392 using namespace chrono;
393 system_clock::time_point __s_now = system_clock::now();
394 typename _Clock::time_point __c_now = _Clock::now();
395 __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__t - __c_now));
396 return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
397}
398
399template <class _Clock, class _Duration, class _Predicate>
400bool
401condition_variable::wait_until(unique_lock<mutex>& __lk,
402 const chrono::time_point<_Clock, _Duration>& __t,
403 _Predicate __pred)
404{
405 while (!__pred())
406 {
407 if (wait_until(__lk, __t) == cv_status::timeout)
408 return __pred();
409 }
410 return true;
411}
412
413template <class _Rep, class _Period>
414cv_status
415condition_variable::wait_for(unique_lock<mutex>& __lk,
416 const chrono::duration<_Rep, _Period>& __d)
417{
418 using namespace chrono;
Howard Hinnantf8f85212010-11-20 19:16:30 +0000419 system_clock::time_point __s_now = system_clock::now();
420 steady_clock::time_point __c_now = steady_clock::now();
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000421 __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d));
Howard Hinnantf8f85212010-11-20 19:16:30 +0000422 return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
423 cv_status::timeout;
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000424}
425
426template <class _Rep, class _Period, class _Predicate>
Howard Hinnant333f50d2010-09-21 20:16:37 +0000427inline _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000428bool
429condition_variable::wait_for(unique_lock<mutex>& __lk,
430 const chrono::duration<_Rep, _Period>& __d,
431 _Predicate __pred)
432{
Howard Hinnantf8f85212010-11-20 19:16:30 +0000433 return wait_until(__lk, chrono::steady_clock::now() + __d,
Howard Hinnant0949eed2011-06-30 21:18:19 +0000434 _VSTD::move(__pred));
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000435}
436
437_LIBCPP_END_NAMESPACE_STD
438
439#endif // _LIBCPP___MUTEX_BASE