blob: ea73d46ed262061f74078c5a4ece871997fc64de [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//
6// This file is distributed under the University of Illinois Open Source
7// License. See LICENSE.TXT for details.
8//
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>
178
179#pragma GCC system_header
180
181_LIBCPP_BEGIN_NAMESPACE_STD
182
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000183class _LIBCPP_VISIBLE recursive_mutex
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000184{
185 pthread_mutex_t __m_;
186
187public:
188 recursive_mutex();
189 ~recursive_mutex();
190
191private:
192 recursive_mutex(const recursive_mutex&); // = delete;
193 recursive_mutex& operator=(const recursive_mutex&); // = delete;
194
195public:
196 void lock();
197 bool try_lock();
198 void unlock();
199
200 typedef pthread_mutex_t* native_handle_type;
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000201 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000202 native_handle_type native_handle() {return &__m_;}
203};
204
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000205class _LIBCPP_VISIBLE timed_mutex
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000206{
207 mutex __m_;
208 condition_variable __cv_;
209 bool __locked_;
210public:
211 timed_mutex();
212 ~timed_mutex();
213
214private:
215 timed_mutex(const timed_mutex&); // = delete;
216 timed_mutex& operator=(const timed_mutex&); // = delete;
217
218public:
219 void lock();
220 bool try_lock();
221 template <class _Rep, class _Period>
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000222 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000223 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
224 {return try_lock_until(chrono::monotonic_clock::now() + __d);}
225 template <class _Clock, class _Duration>
226 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
227 void unlock();
228};
229
230template <class _Clock, class _Duration>
231bool
232timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
233{
234 using namespace chrono;
235 unique_lock<mutex> __lk(__m_);
236 bool no_timeout = _Clock::now() < __t;
237 while (no_timeout && __locked_)
238 no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout;
239 if (!__locked_)
240 {
241 __locked_ = true;
242 return true;
243 }
244 return false;
245}
246
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000247class _LIBCPP_VISIBLE recursive_timed_mutex
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000248{
249 mutex __m_;
250 condition_variable __cv_;
251 size_t __count_;
252 pthread_t __id_;
253public:
254 recursive_timed_mutex();
255 ~recursive_timed_mutex();
256
257private:
258 recursive_timed_mutex(const recursive_timed_mutex&); // = delete;
259 recursive_timed_mutex& operator=(const recursive_timed_mutex&); // = delete;
260
261public:
262 void lock();
263 bool try_lock();
264 template <class _Rep, class _Period>
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000265 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000266 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
267 {return try_lock_until(chrono::monotonic_clock::now() + __d);}
268 template <class _Clock, class _Duration>
269 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
270 void unlock();
271};
272
273template <class _Clock, class _Duration>
274bool
275recursive_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
276{
277 using namespace chrono;
278 pthread_t __id = pthread_self();
279 unique_lock<mutex> lk(__m_);
280 if (pthread_equal(__id, __id_))
281 {
282 if (__count_ == numeric_limits<size_t>::max())
283 return false;
284 ++__count_;
285 return true;
286 }
287 bool no_timeout = _Clock::now() < __t;
288 while (no_timeout && __count_ != 0)
289 no_timeout = __cv_.wait_until(lk, __t) == cv_status::no_timeout;
290 if (__count_ == 0)
291 {
292 __count_ = 1;
293 __id_ = __id;
294 return true;
295 }
296 return false;
297}
298
299template <class _L0, class _L1>
300int
301try_lock(_L0& __l0, _L1& __l1)
302{
303 unique_lock<_L0> __u0(__l0, try_to_lock);
304 if (__u0.owns_lock())
305 {
306 if (__l1.try_lock())
307 {
308 __u0.release();
309 return -1;
310 }
311 else
312 return 1;
313 }
314 return 0;
315}
316
317#ifndef _LIBCPP_HAS_NO_VARIADICS
318
319template <class _L0, class _L1, class _L2, class... _L3>
320int
321try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3)
322{
323 int __r = 0;
324 unique_lock<_L0> __u0(__l0, try_to_lock);
325 if (__u0.owns_lock())
326 {
327 __r = try_lock(__l1, __l2, __l3...);
328 if (__r == -1)
329 __u0.release();
330 else
331 ++__r;
332 }
333 return __r;
334}
335
Howard Hinnant324bb032010-08-22 00:02:43 +0000336#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000337
338template <class _L0, class _L1>
339void
340lock(_L0& __l0, _L1& __l1)
341{
342 while (true)
343 {
344 {
345 unique_lock<_L0> __u0(__l0);
346 if (__l1.try_lock())
347 {
348 __u0.release();
349 break;
350 }
351 }
352 sched_yield();
353 {
354 unique_lock<_L1> __u1(__l1);
355 if (__l0.try_lock())
356 {
357 __u1.release();
358 break;
359 }
360 }
361 sched_yield();
362 }
363}
364
365#ifndef _LIBCPP_HAS_NO_VARIADICS
366
367template <class _L0, class _L1, class ..._L2>
368void
369__lock_first(int __i, _L0& __l0, _L1& __l1, _L2& ...__l2)
370{
371 while (true)
372 {
373 switch (__i)
374 {
375 case 0:
376 {
377 unique_lock<_L0> __u0(__l0);
378 __i = try_lock(__l1, __l2...);
379 if (__i == -1)
380 {
381 __u0.release();
382 return;
383 }
384 }
385 ++__i;
386 sched_yield();
387 break;
388 case 1:
389 {
390 unique_lock<_L1> __u1(__l1);
391 __i = try_lock(__l2..., __l0);
392 if (__i == -1)
393 {
394 __u1.release();
395 return;
396 }
397 }
398 if (__i == sizeof...(_L2))
399 __i = 0;
400 else
401 __i += 2;
402 sched_yield();
403 break;
404 default:
405 __lock_first(__i - 2, __l2..., __l0, __l1);
406 return;
407 }
408 }
409}
410
411template <class _L0, class _L1, class ..._L2>
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000412inline _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000413void
414lock(_L0& __l0, _L1& __l1, _L2& ...__l2)
415{
416 __lock_first(0, __l0, __l1, __l2...);
417}
418
Howard Hinnant324bb032010-08-22 00:02:43 +0000419#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000420
421struct once_flag;
422
423#ifndef _LIBCPP_HAS_NO_VARIADICS
424
425template<class _Callable, class... _Args>
426 void call_once(once_flag&, _Callable&&, _Args&&...);
427
Howard Hinnant324bb032010-08-22 00:02:43 +0000428#else // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000429
430template<class _Callable>
431 void call_once(once_flag&, _Callable);
432
Howard Hinnant324bb032010-08-22 00:02:43 +0000433#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000434
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000435struct _LIBCPP_VISIBLE once_flag
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000436{
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000437 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000438 // constexpr
439 once_flag() {}
440
441private:
442 once_flag(const once_flag&); // = delete;
443 once_flag& operator=(const once_flag&); // = delete;
444
445 unsigned long __state_;
446
447#ifndef _LIBCPP_HAS_NO_VARIADICS
448 template<class _Callable, class... _Args>
449 friend
450 void call_once(once_flag&, _Callable&&, _Args&&...);
Howard Hinnant324bb032010-08-22 00:02:43 +0000451#else // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000452 template<class _Callable>
453 friend
454 void call_once(once_flag&, _Callable);
Howard Hinnant324bb032010-08-22 00:02:43 +0000455#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000456};
457
458template <class _F>
459class __call_once_param
460{
461 _F __f_;
462public:
Howard Hinnant73d21a42010-09-04 23:28:19 +0000463#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000464 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000465 explicit __call_once_param(_F&& __f) : __f_(_STD::move(__f)) {}
466#else
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000467 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000468 explicit __call_once_param(const _F& __f) : __f_(__f) {}
469#endif
470
Howard Hinnantb9af2ea2010-09-22 18:02:38 +0000471 _LIBCPP_INLINE_VISIBILITY
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000472 void operator()()
473 {
474 __f_();
475 }
476};
477
478template <class _F>
479void
480__call_once_proxy(void* __vp)
481{
482 __call_once_param<_F>* __p = static_cast<__call_once_param<_F>*>(__vp);
483 (*__p)();
484}
485
486void __call_once(volatile unsigned long&, void*, void(*)(void*));
487
488#ifndef _LIBCPP_HAS_NO_VARIADICS
489
490template<class _Callable, class... _Args>
491inline _LIBCPP_INLINE_VISIBILITY
492void
493call_once(once_flag& __flag, _Callable&& __func, _Args&&... __args)
494{
495 if (__builtin_expect(__flag.__state_ , ~0ul) != ~0ul)
496 {
497 typedef decltype(std::bind(std::forward<_Callable>(__func),
498 std::forward<_Args>(__args)...)) _G;
499 __call_once_param<_G> __p(std::bind(std::forward<_Callable>(__func),
500 std::forward<_Args>(__args)...));
501 __call_once(__flag.__state_, &__p, &__call_once_proxy<_G>);
502 }
503}
504
Howard Hinnant324bb032010-08-22 00:02:43 +0000505#else // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000506
507template<class _Callable>
508inline _LIBCPP_INLINE_VISIBILITY
509void
510call_once(once_flag& __flag, _Callable __func)
511{
512 if (__flag.__state_ != ~0ul)
513 {
514 __call_once_param<_Callable> __p(__func);
515 __call_once(__flag.__state_, &__p, &__call_once_proxy<_Callable>);
516 }
517}
518
Howard Hinnant324bb032010-08-22 00:02:43 +0000519#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000520
521_LIBCPP_END_NAMESPACE_STD
522
523#endif // _LIBCPP_MUTEX