blob: 37e74d6d5752dace9ff7893374819f6b2d9a84be [file] [log] [blame]
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001// -*- C++ -*-
2//===--------------------------- mutex ------------------------------------===//
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
12#define _LIBCPP_MUTEX
13
14/*
15 mutex synopsis
16
17namespace std
18{
19
20class mutex
21{
22public:
23 mutex();
24 ~mutex();
25
26 mutex(const mutex&) = delete;
27 mutex& operator=(const mutex&) = delete;
28
29 void lock();
30 bool try_lock();
31 void unlock();
32
33 typedef pthread_mutex_t* native_handle_type;
34 native_handle_type native_handle();
35};
36
37class recursive_mutex
38{
39public:
40 recursive_mutex();
41 ~recursive_mutex();
42
43 recursive_mutex(const recursive_mutex&) = delete;
44 recursive_mutex& operator=(const recursive_mutex&) = delete;
45
46 void lock();
47 bool try_lock();
48 void unlock();
49
50 typedef pthread_mutex_t* native_handle_type;
51 native_handle_type native_handle();
52};
53
54class timed_mutex
55{
56public:
57 timed_mutex();
58 ~timed_mutex();
59
60 timed_mutex(const timed_mutex&) = delete;
61 timed_mutex& operator=(const timed_mutex&) = delete;
62
63 void lock();
64 bool try_lock();
65 template <class Rep, class Period>
66 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
67 template <class Clock, class Duration>
68 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
69 void unlock();
70};
71
72class recursive_timed_mutex
73{
74public:
75 recursive_timed_mutex();
76 ~recursive_timed_mutex();
77
78 recursive_timed_mutex(const recursive_timed_mutex&) = delete;
79 recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
80
81 void lock();
82 bool try_lock();
83 template <class Rep, class Period>
84 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
85 template <class Clock, class Duration>
86 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
87 void unlock();
88};
89
90struct defer_lock_t {};
91struct try_to_lock_t {};
92struct adopt_lock_t {};
93
94constexpr defer_lock_t defer_lock{};
95constexpr try_to_lock_t try_to_lock{};
96constexpr adopt_lock_t adopt_lock{};
97
98template <class Mutex>
99class lock_guard
100{
101public:
102 typedef Mutex mutex_type;
103
104 explicit lock_guard(mutex_type& m);
105 lock_guard(mutex_type& m, adopt_lock_t);
106 ~lock_guard();
107
108 lock_guard(lock_guard const&) = delete;
109 lock_guard& operator=(lock_guard const&) = delete;
110};
111
112template <class Mutex>
113class unique_lock
114{
115public:
116 typedef Mutex mutex_type;
117 unique_lock();
118 explicit unique_lock(mutex_type& m);
119 unique_lock(mutex_type& m, defer_lock_t);
120 unique_lock(mutex_type& m, try_to_lock_t);
121 unique_lock(mutex_type& m, adopt_lock_t);
122 template <class Clock, class Duration>
123 unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
124 template <class Rep, class Period>
125 unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
126 ~unique_lock();
127
128 unique_lock(unique_lock const&) = delete;
129 unique_lock& operator=(unique_lock const&) = delete;
130
131 unique_lock(unique_lock&& u);
132 unique_lock& operator=(unique_lock&& u);
133
134 void lock();
135 bool try_lock();
136
137 template <class Rep, class Period>
138 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
139 template <class Clock, class Duration>
140 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
141
142 void unlock();
143
144 void swap(unique_lock& u);
145 mutex_type* release();
146
147 bool owns_lock() const;
148 explicit operator bool () const;
149 mutex_type* mutex() const;
150};
151
152template <class Mutex>
153 void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y);
154
155template <class L1, class L2, class... L3>
156 int try_lock(L1&, L2&, L3&...);
157template <class L1, class L2, class... L3>
158 void lock(L1&, L2&, L3&...);
159
160struct once_flag
161{
162 constexpr once_flag();
163
164 once_flag(const once_flag&) = delete;
165 once_flag& operator=(const once_flag&) = delete;
166};
167
168template<class Callable, class ...Args>
169 void call_once(once_flag& flag, Callable&& func, Args&&... args);
170
171} // std
172
173*/
174
175#include <__config>
176#include <__mutex_base>
177#include <functional>
Howard Hinnantad935d52011-05-16 19:05:11 +0000178#ifndef _LIBCPP_HAS_NO_VARIADICS
179#include <tuple>
180#endif
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000181
Howard Hinnant08e17472011-10-17 20:05:10 +0000182#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000183#pragma GCC system_header
Howard Hinnant08e17472011-10-17 20:05:10 +0000184#endif
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000185
186_LIBCPP_BEGIN_NAMESPACE_STD
187
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000188class _LIBCPP_VISIBLE recursive_mutex
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000189{
190 pthread_mutex_t __m_;
191
192public:
193 recursive_mutex();
194 ~recursive_mutex();
195
196private:
197 recursive_mutex(const recursive_mutex&); // = delete;
198 recursive_mutex& operator=(const recursive_mutex&); // = delete;
199
200public:
201 void lock();
202 bool try_lock();
203 void unlock();
204
205 typedef pthread_mutex_t* native_handle_type;
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000206 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000207 native_handle_type native_handle() {return &__m_;}
208};
209
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000210class _LIBCPP_VISIBLE timed_mutex
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000211{
212 mutex __m_;
213 condition_variable __cv_;
214 bool __locked_;
215public:
216 timed_mutex();
217 ~timed_mutex();
218
219private:
220 timed_mutex(const timed_mutex&); // = delete;
221 timed_mutex& operator=(const timed_mutex&); // = delete;
222
223public:
224 void lock();
225 bool try_lock();
226 template <class _Rep, class _Period>
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000227 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000228 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
Howard Hinnantf8f85212010-11-20 19:16:30 +0000229 {return try_lock_until(chrono::steady_clock::now() + __d);}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000230 template <class _Clock, class _Duration>
231 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
232 void unlock();
233};
234
235template <class _Clock, class _Duration>
236bool
237timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
238{
239 using namespace chrono;
240 unique_lock<mutex> __lk(__m_);
241 bool no_timeout = _Clock::now() < __t;
242 while (no_timeout && __locked_)
243 no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout;
244 if (!__locked_)
245 {
246 __locked_ = true;
247 return true;
248 }
249 return false;
250}
251
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000252class _LIBCPP_VISIBLE recursive_timed_mutex
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000253{
254 mutex __m_;
255 condition_variable __cv_;
256 size_t __count_;
257 pthread_t __id_;
258public:
259 recursive_timed_mutex();
260 ~recursive_timed_mutex();
261
262private:
263 recursive_timed_mutex(const recursive_timed_mutex&); // = delete;
264 recursive_timed_mutex& operator=(const recursive_timed_mutex&); // = delete;
265
266public:
267 void lock();
268 bool try_lock();
269 template <class _Rep, class _Period>
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000270 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000271 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
Howard Hinnantf8f85212010-11-20 19:16:30 +0000272 {return try_lock_until(chrono::steady_clock::now() + __d);}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000273 template <class _Clock, class _Duration>
274 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
275 void unlock();
276};
277
278template <class _Clock, class _Duration>
279bool
280recursive_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
281{
282 using namespace chrono;
283 pthread_t __id = pthread_self();
284 unique_lock<mutex> lk(__m_);
285 if (pthread_equal(__id, __id_))
286 {
287 if (__count_ == numeric_limits<size_t>::max())
288 return false;
289 ++__count_;
290 return true;
291 }
292 bool no_timeout = _Clock::now() < __t;
293 while (no_timeout && __count_ != 0)
294 no_timeout = __cv_.wait_until(lk, __t) == cv_status::no_timeout;
295 if (__count_ == 0)
296 {
297 __count_ = 1;
298 __id_ = __id;
299 return true;
300 }
301 return false;
302}
303
304template <class _L0, class _L1>
305int
306try_lock(_L0& __l0, _L1& __l1)
307{
308 unique_lock<_L0> __u0(__l0, try_to_lock);
309 if (__u0.owns_lock())
310 {
311 if (__l1.try_lock())
312 {
313 __u0.release();
314 return -1;
315 }
316 else
317 return 1;
318 }
319 return 0;
320}
321
322#ifndef _LIBCPP_HAS_NO_VARIADICS
323
324template <class _L0, class _L1, class _L2, class... _L3>
325int
326try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3)
327{
328 int __r = 0;
329 unique_lock<_L0> __u0(__l0, try_to_lock);
330 if (__u0.owns_lock())
331 {
332 __r = try_lock(__l1, __l2, __l3...);
333 if (__r == -1)
334 __u0.release();
335 else
336 ++__r;
337 }
338 return __r;
339}
340
Howard Hinnant324bb032010-08-22 00:02:43 +0000341#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000342
343template <class _L0, class _L1>
344void
345lock(_L0& __l0, _L1& __l1)
346{
347 while (true)
348 {
349 {
350 unique_lock<_L0> __u0(__l0);
351 if (__l1.try_lock())
352 {
353 __u0.release();
354 break;
355 }
356 }
357 sched_yield();
358 {
359 unique_lock<_L1> __u1(__l1);
360 if (__l0.try_lock())
361 {
362 __u1.release();
363 break;
364 }
365 }
366 sched_yield();
367 }
368}
369
370#ifndef _LIBCPP_HAS_NO_VARIADICS
371
Howard Hinnant6fd4b662011-01-12 22:56:59 +0000372template <class _L0, class _L1, class _L2, class ..._L3>
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000373void
Howard Hinnant6fd4b662011-01-12 22:56:59 +0000374__lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000375{
376 while (true)
377 {
378 switch (__i)
379 {
380 case 0:
381 {
382 unique_lock<_L0> __u0(__l0);
Howard Hinnant6fd4b662011-01-12 22:56:59 +0000383 __i = try_lock(__l1, __l2, __l3...);
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000384 if (__i == -1)
385 {
386 __u0.release();
387 return;
388 }
389 }
390 ++__i;
391 sched_yield();
392 break;
393 case 1:
394 {
395 unique_lock<_L1> __u1(__l1);
Howard Hinnant6fd4b662011-01-12 22:56:59 +0000396 __i = try_lock(__l2, __l3..., __l0);
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000397 if (__i == -1)
398 {
399 __u1.release();
400 return;
401 }
402 }
Howard Hinnant6fd4b662011-01-12 22:56:59 +0000403 if (__i == sizeof...(_L3) + 1)
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000404 __i = 0;
405 else
406 __i += 2;
407 sched_yield();
408 break;
409 default:
Howard Hinnant6fd4b662011-01-12 22:56:59 +0000410 __lock_first(__i - 2, __l2, __l3..., __l0, __l1);
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000411 return;
412 }
413 }
414}
415
Howard Hinnant6fd4b662011-01-12 22:56:59 +0000416template <class _L0, class _L1, class _L2, class ..._L3>
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000417inline _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000418void
Howard Hinnant6fd4b662011-01-12 22:56:59 +0000419lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000420{
Howard Hinnant6fd4b662011-01-12 22:56:59 +0000421 __lock_first(0, __l0, __l1, __l2, __l3...);
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000422}
423
Howard Hinnant324bb032010-08-22 00:02:43 +0000424#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000425
426struct once_flag;
427
428#ifndef _LIBCPP_HAS_NO_VARIADICS
429
430template<class _Callable, class... _Args>
431 void call_once(once_flag&, _Callable&&, _Args&&...);
432
Howard Hinnant324bb032010-08-22 00:02:43 +0000433#else // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000434
435template<class _Callable>
436 void call_once(once_flag&, _Callable);
437
Howard Hinnant324bb032010-08-22 00:02:43 +0000438#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000439
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000440struct _LIBCPP_VISIBLE once_flag
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000441{
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000442 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000443 // constexpr
444 once_flag() {}
445
446private:
447 once_flag(const once_flag&); // = delete;
448 once_flag& operator=(const once_flag&); // = delete;
449
450 unsigned long __state_;
451
452#ifndef _LIBCPP_HAS_NO_VARIADICS
453 template<class _Callable, class... _Args>
454 friend
455 void call_once(once_flag&, _Callable&&, _Args&&...);
Howard Hinnant324bb032010-08-22 00:02:43 +0000456#else // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000457 template<class _Callable>
458 friend
459 void call_once(once_flag&, _Callable);
Howard Hinnant324bb032010-08-22 00:02:43 +0000460#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000461};
462
Howard Hinnantad935d52011-05-16 19:05:11 +0000463#ifndef _LIBCPP_HAS_NO_VARIADICS
464
465template <class _F>
466class __call_once_param
467{
468 _F __f_;
469public:
470#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
471 _LIBCPP_INLINE_VISIBILITY
Howard Hinnant0949eed2011-06-30 21:18:19 +0000472 explicit __call_once_param(_F&& __f) : __f_(_VSTD::move(__f)) {}
Howard Hinnantad935d52011-05-16 19:05:11 +0000473#else
474 _LIBCPP_INLINE_VISIBILITY
475 explicit __call_once_param(const _F& __f) : __f_(__f) {}
476#endif
477
478 _LIBCPP_INLINE_VISIBILITY
479 void operator()()
480 {
481 typedef typename __make_tuple_indices<tuple_size<_F>::value, 1>::type _Index;
482 __execute(_Index());
483 }
484
485private:
486 template <size_t ..._Indices>
487 _LIBCPP_INLINE_VISIBILITY
488 void __execute(__tuple_indices<_Indices...>)
489 {
Howard Hinnant0949eed2011-06-30 21:18:19 +0000490 __invoke(_VSTD::move(_VSTD::get<0>(__f_)), _VSTD::move(_VSTD::get<_Indices>(__f_))...);
Howard Hinnantad935d52011-05-16 19:05:11 +0000491 }
492};
493
494#else
495
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000496template <class _F>
497class __call_once_param
498{
499 _F __f_;
500public:
Howard Hinnant73d21a42010-09-04 23:28:19 +0000501#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000502 _LIBCPP_INLINE_VISIBILITY
Howard Hinnant0949eed2011-06-30 21:18:19 +0000503 explicit __call_once_param(_F&& __f) : __f_(_VSTD::move(__f)) {}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000504#else
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000505 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000506 explicit __call_once_param(const _F& __f) : __f_(__f) {}
507#endif
508
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000509 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000510 void operator()()
511 {
512 __f_();
513 }
514};
515
Howard Hinnantad935d52011-05-16 19:05:11 +0000516#endif
517
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000518template <class _F>
519void
520__call_once_proxy(void* __vp)
521{
522 __call_once_param<_F>* __p = static_cast<__call_once_param<_F>*>(__vp);
523 (*__p)();
524}
525
526void __call_once(volatile unsigned long&, void*, void(*)(void*));
527
528#ifndef _LIBCPP_HAS_NO_VARIADICS
529
530template<class _Callable, class... _Args>
531inline _LIBCPP_INLINE_VISIBILITY
532void
533call_once(once_flag& __flag, _Callable&& __func, _Args&&... __args)
534{
535 if (__builtin_expect(__flag.__state_ , ~0ul) != ~0ul)
536 {
Howard Hinnantad935d52011-05-16 19:05:11 +0000537 typedef tuple<typename decay<_Callable>::type, typename decay<_Args>::type...> _G;
Howard Hinnant0949eed2011-06-30 21:18:19 +0000538 __call_once_param<_G> __p(_G(__decay_copy(_VSTD::forward<_Callable>(__func)),
539 __decay_copy(_VSTD::forward<_Args>(__args))...));
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000540 __call_once(__flag.__state_, &__p, &__call_once_proxy<_G>);
541 }
542}
543
Howard Hinnant324bb032010-08-22 00:02:43 +0000544#else // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000545
546template<class _Callable>
547inline _LIBCPP_INLINE_VISIBILITY
548void
549call_once(once_flag& __flag, _Callable __func)
550{
551 if (__flag.__state_ != ~0ul)
552 {
553 __call_once_param<_Callable> __p(__func);
554 __call_once(__flag.__state_, &__p, &__call_once_proxy<_Callable>);
555 }
556}
557
Howard Hinnant324bb032010-08-22 00:02:43 +0000558#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000559
560_LIBCPP_END_NAMESPACE_STD
561
562#endif // _LIBCPP_MUTEX