blob: 69192a82f3d52d715bf090e17266e47135722b2f [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
182#pragma GCC system_header
183
184_LIBCPP_BEGIN_NAMESPACE_STD
185
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000186class _LIBCPP_VISIBLE recursive_mutex
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000187{
188 pthread_mutex_t __m_;
189
190public:
191 recursive_mutex();
192 ~recursive_mutex();
193
194private:
195 recursive_mutex(const recursive_mutex&); // = delete;
196 recursive_mutex& operator=(const recursive_mutex&); // = delete;
197
198public:
199 void lock();
200 bool try_lock();
201 void unlock();
202
203 typedef pthread_mutex_t* native_handle_type;
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000204 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000205 native_handle_type native_handle() {return &__m_;}
206};
207
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000208class _LIBCPP_VISIBLE timed_mutex
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000209{
210 mutex __m_;
211 condition_variable __cv_;
212 bool __locked_;
213public:
214 timed_mutex();
215 ~timed_mutex();
216
217private:
218 timed_mutex(const timed_mutex&); // = delete;
219 timed_mutex& operator=(const timed_mutex&); // = delete;
220
221public:
222 void lock();
223 bool try_lock();
224 template <class _Rep, class _Period>
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000225 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000226 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
Howard Hinnantf8f85212010-11-20 19:16:30 +0000227 {return try_lock_until(chrono::steady_clock::now() + __d);}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000228 template <class _Clock, class _Duration>
229 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
230 void unlock();
231};
232
233template <class _Clock, class _Duration>
234bool
235timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
236{
237 using namespace chrono;
238 unique_lock<mutex> __lk(__m_);
239 bool no_timeout = _Clock::now() < __t;
240 while (no_timeout && __locked_)
241 no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout;
242 if (!__locked_)
243 {
244 __locked_ = true;
245 return true;
246 }
247 return false;
248}
249
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000250class _LIBCPP_VISIBLE recursive_timed_mutex
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000251{
252 mutex __m_;
253 condition_variable __cv_;
254 size_t __count_;
255 pthread_t __id_;
256public:
257 recursive_timed_mutex();
258 ~recursive_timed_mutex();
259
260private:
261 recursive_timed_mutex(const recursive_timed_mutex&); // = delete;
262 recursive_timed_mutex& operator=(const recursive_timed_mutex&); // = delete;
263
264public:
265 void lock();
266 bool try_lock();
267 template <class _Rep, class _Period>
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000268 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000269 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
Howard Hinnantf8f85212010-11-20 19:16:30 +0000270 {return try_lock_until(chrono::steady_clock::now() + __d);}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000271 template <class _Clock, class _Duration>
272 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
273 void unlock();
274};
275
276template <class _Clock, class _Duration>
277bool
278recursive_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
279{
280 using namespace chrono;
281 pthread_t __id = pthread_self();
282 unique_lock<mutex> lk(__m_);
283 if (pthread_equal(__id, __id_))
284 {
285 if (__count_ == numeric_limits<size_t>::max())
286 return false;
287 ++__count_;
288 return true;
289 }
290 bool no_timeout = _Clock::now() < __t;
291 while (no_timeout && __count_ != 0)
292 no_timeout = __cv_.wait_until(lk, __t) == cv_status::no_timeout;
293 if (__count_ == 0)
294 {
295 __count_ = 1;
296 __id_ = __id;
297 return true;
298 }
299 return false;
300}
301
302template <class _L0, class _L1>
303int
304try_lock(_L0& __l0, _L1& __l1)
305{
306 unique_lock<_L0> __u0(__l0, try_to_lock);
307 if (__u0.owns_lock())
308 {
309 if (__l1.try_lock())
310 {
311 __u0.release();
312 return -1;
313 }
314 else
315 return 1;
316 }
317 return 0;
318}
319
320#ifndef _LIBCPP_HAS_NO_VARIADICS
321
322template <class _L0, class _L1, class _L2, class... _L3>
323int
324try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3)
325{
326 int __r = 0;
327 unique_lock<_L0> __u0(__l0, try_to_lock);
328 if (__u0.owns_lock())
329 {
330 __r = try_lock(__l1, __l2, __l3...);
331 if (__r == -1)
332 __u0.release();
333 else
334 ++__r;
335 }
336 return __r;
337}
338
Howard Hinnant324bb032010-08-22 00:02:43 +0000339#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000340
341template <class _L0, class _L1>
342void
343lock(_L0& __l0, _L1& __l1)
344{
345 while (true)
346 {
347 {
348 unique_lock<_L0> __u0(__l0);
349 if (__l1.try_lock())
350 {
351 __u0.release();
352 break;
353 }
354 }
355 sched_yield();
356 {
357 unique_lock<_L1> __u1(__l1);
358 if (__l0.try_lock())
359 {
360 __u1.release();
361 break;
362 }
363 }
364 sched_yield();
365 }
366}
367
368#ifndef _LIBCPP_HAS_NO_VARIADICS
369
Howard Hinnant6fd4b662011-01-12 22:56:59 +0000370template <class _L0, class _L1, class _L2, class ..._L3>
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000371void
Howard Hinnant6fd4b662011-01-12 22:56:59 +0000372__lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000373{
374 while (true)
375 {
376 switch (__i)
377 {
378 case 0:
379 {
380 unique_lock<_L0> __u0(__l0);
Howard Hinnant6fd4b662011-01-12 22:56:59 +0000381 __i = try_lock(__l1, __l2, __l3...);
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000382 if (__i == -1)
383 {
384 __u0.release();
385 return;
386 }
387 }
388 ++__i;
389 sched_yield();
390 break;
391 case 1:
392 {
393 unique_lock<_L1> __u1(__l1);
Howard Hinnant6fd4b662011-01-12 22:56:59 +0000394 __i = try_lock(__l2, __l3..., __l0);
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000395 if (__i == -1)
396 {
397 __u1.release();
398 return;
399 }
400 }
Howard Hinnant6fd4b662011-01-12 22:56:59 +0000401 if (__i == sizeof...(_L3) + 1)
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000402 __i = 0;
403 else
404 __i += 2;
405 sched_yield();
406 break;
407 default:
Howard Hinnant6fd4b662011-01-12 22:56:59 +0000408 __lock_first(__i - 2, __l2, __l3..., __l0, __l1);
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000409 return;
410 }
411 }
412}
413
Howard Hinnant6fd4b662011-01-12 22:56:59 +0000414template <class _L0, class _L1, class _L2, class ..._L3>
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000415inline _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000416void
Howard Hinnant6fd4b662011-01-12 22:56:59 +0000417lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000418{
Howard Hinnant6fd4b662011-01-12 22:56:59 +0000419 __lock_first(0, __l0, __l1, __l2, __l3...);
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000420}
421
Howard Hinnant324bb032010-08-22 00:02:43 +0000422#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000423
424struct once_flag;
425
426#ifndef _LIBCPP_HAS_NO_VARIADICS
427
428template<class _Callable, class... _Args>
429 void call_once(once_flag&, _Callable&&, _Args&&...);
430
Howard Hinnant324bb032010-08-22 00:02:43 +0000431#else // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000432
433template<class _Callable>
434 void call_once(once_flag&, _Callable);
435
Howard Hinnant324bb032010-08-22 00:02:43 +0000436#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000437
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000438struct _LIBCPP_VISIBLE once_flag
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000439{
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000440 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000441 // constexpr
442 once_flag() {}
443
444private:
445 once_flag(const once_flag&); // = delete;
446 once_flag& operator=(const once_flag&); // = delete;
447
448 unsigned long __state_;
449
450#ifndef _LIBCPP_HAS_NO_VARIADICS
451 template<class _Callable, class... _Args>
452 friend
453 void call_once(once_flag&, _Callable&&, _Args&&...);
Howard Hinnant324bb032010-08-22 00:02:43 +0000454#else // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000455 template<class _Callable>
456 friend
457 void call_once(once_flag&, _Callable);
Howard Hinnant324bb032010-08-22 00:02:43 +0000458#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000459};
460
Howard Hinnantad935d52011-05-16 19:05:11 +0000461#ifndef _LIBCPP_HAS_NO_VARIADICS
462
463template <class _F>
464class __call_once_param
465{
466 _F __f_;
467public:
468#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
469 _LIBCPP_INLINE_VISIBILITY
470 explicit __call_once_param(_F&& __f) : __f_(_STD::move(__f)) {}
471#else
472 _LIBCPP_INLINE_VISIBILITY
473 explicit __call_once_param(const _F& __f) : __f_(__f) {}
474#endif
475
476 _LIBCPP_INLINE_VISIBILITY
477 void operator()()
478 {
479 typedef typename __make_tuple_indices<tuple_size<_F>::value, 1>::type _Index;
480 __execute(_Index());
481 }
482
483private:
484 template <size_t ..._Indices>
485 _LIBCPP_INLINE_VISIBILITY
486 void __execute(__tuple_indices<_Indices...>)
487 {
Howard Hinnant57cff292011-05-19 15:05:04 +0000488 __invoke(_STD::move(_STD::get<0>(__f_)), _STD::move(_STD::get<_Indices>(__f_))...);
Howard Hinnantad935d52011-05-16 19:05:11 +0000489 }
490};
491
492#else
493
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000494template <class _F>
495class __call_once_param
496{
497 _F __f_;
498public:
Howard Hinnant73d21a42010-09-04 23:28:19 +0000499#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000500 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000501 explicit __call_once_param(_F&& __f) : __f_(_STD::move(__f)) {}
502#else
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000503 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000504 explicit __call_once_param(const _F& __f) : __f_(__f) {}
505#endif
506
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000507 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000508 void operator()()
509 {
510 __f_();
511 }
512};
513
Howard Hinnantad935d52011-05-16 19:05:11 +0000514#endif
515
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000516template <class _F>
517void
518__call_once_proxy(void* __vp)
519{
520 __call_once_param<_F>* __p = static_cast<__call_once_param<_F>*>(__vp);
521 (*__p)();
522}
523
524void __call_once(volatile unsigned long&, void*, void(*)(void*));
525
526#ifndef _LIBCPP_HAS_NO_VARIADICS
527
528template<class _Callable, class... _Args>
529inline _LIBCPP_INLINE_VISIBILITY
530void
531call_once(once_flag& __flag, _Callable&& __func, _Args&&... __args)
532{
533 if (__builtin_expect(__flag.__state_ , ~0ul) != ~0ul)
534 {
Howard Hinnantad935d52011-05-16 19:05:11 +0000535 typedef tuple<typename decay<_Callable>::type, typename decay<_Args>::type...> _G;
536 __call_once_param<_G> __p(_G(__decay_copy(_STD::forward<_Callable>(__func)),
537 __decay_copy(_STD::forward<_Args>(__args))...));
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000538 __call_once(__flag.__state_, &__p, &__call_once_proxy<_G>);
539 }
540}
541
Howard Hinnant324bb032010-08-22 00:02:43 +0000542#else // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000543
544template<class _Callable>
545inline _LIBCPP_INLINE_VISIBILITY
546void
547call_once(once_flag& __flag, _Callable __func)
548{
549 if (__flag.__state_ != ~0ul)
550 {
551 __call_once_param<_Callable> __p(__func);
552 __call_once(__flag.__state_, &__p, &__call_once_proxy<_Callable>);
553 }
554}
555
Howard Hinnant324bb032010-08-22 00:02:43 +0000556#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000557
558_LIBCPP_END_NAMESPACE_STD
559
560#endif // _LIBCPP_MUTEX