blob: 8ab9c2ae5ebf16df4a9dc5b4de4f75de3dbbc151 [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
183class recursive_mutex
184{
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;
201 native_handle_type native_handle() {return &__m_;}
202};
203
204class timed_mutex
205{
206 mutex __m_;
207 condition_variable __cv_;
208 bool __locked_;
209public:
210 timed_mutex();
211 ~timed_mutex();
212
213private:
214 timed_mutex(const timed_mutex&); // = delete;
215 timed_mutex& operator=(const timed_mutex&); // = delete;
216
217public:
218 void lock();
219 bool try_lock();
220 template <class _Rep, class _Period>
221 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
222 {return try_lock_until(chrono::monotonic_clock::now() + __d);}
223 template <class _Clock, class _Duration>
224 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
225 void unlock();
226};
227
228template <class _Clock, class _Duration>
229bool
230timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
231{
232 using namespace chrono;
233 unique_lock<mutex> __lk(__m_);
234 bool no_timeout = _Clock::now() < __t;
235 while (no_timeout && __locked_)
236 no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout;
237 if (!__locked_)
238 {
239 __locked_ = true;
240 return true;
241 }
242 return false;
243}
244
245class recursive_timed_mutex
246{
247 mutex __m_;
248 condition_variable __cv_;
249 size_t __count_;
250 pthread_t __id_;
251public:
252 recursive_timed_mutex();
253 ~recursive_timed_mutex();
254
255private:
256 recursive_timed_mutex(const recursive_timed_mutex&); // = delete;
257 recursive_timed_mutex& operator=(const recursive_timed_mutex&); // = delete;
258
259public:
260 void lock();
261 bool try_lock();
262 template <class _Rep, class _Period>
263 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
264 {return try_lock_until(chrono::monotonic_clock::now() + __d);}
265 template <class _Clock, class _Duration>
266 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
267 void unlock();
268};
269
270template <class _Clock, class _Duration>
271bool
272recursive_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
273{
274 using namespace chrono;
275 pthread_t __id = pthread_self();
276 unique_lock<mutex> lk(__m_);
277 if (pthread_equal(__id, __id_))
278 {
279 if (__count_ == numeric_limits<size_t>::max())
280 return false;
281 ++__count_;
282 return true;
283 }
284 bool no_timeout = _Clock::now() < __t;
285 while (no_timeout && __count_ != 0)
286 no_timeout = __cv_.wait_until(lk, __t) == cv_status::no_timeout;
287 if (__count_ == 0)
288 {
289 __count_ = 1;
290 __id_ = __id;
291 return true;
292 }
293 return false;
294}
295
296template <class _L0, class _L1>
297int
298try_lock(_L0& __l0, _L1& __l1)
299{
300 unique_lock<_L0> __u0(__l0, try_to_lock);
301 if (__u0.owns_lock())
302 {
303 if (__l1.try_lock())
304 {
305 __u0.release();
306 return -1;
307 }
308 else
309 return 1;
310 }
311 return 0;
312}
313
314#ifndef _LIBCPP_HAS_NO_VARIADICS
315
316template <class _L0, class _L1, class _L2, class... _L3>
317int
318try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3)
319{
320 int __r = 0;
321 unique_lock<_L0> __u0(__l0, try_to_lock);
322 if (__u0.owns_lock())
323 {
324 __r = try_lock(__l1, __l2, __l3...);
325 if (__r == -1)
326 __u0.release();
327 else
328 ++__r;
329 }
330 return __r;
331}
332
Howard Hinnant324bb032010-08-22 00:02:43 +0000333#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000334
335template <class _L0, class _L1>
336void
337lock(_L0& __l0, _L1& __l1)
338{
339 while (true)
340 {
341 {
342 unique_lock<_L0> __u0(__l0);
343 if (__l1.try_lock())
344 {
345 __u0.release();
346 break;
347 }
348 }
349 sched_yield();
350 {
351 unique_lock<_L1> __u1(__l1);
352 if (__l0.try_lock())
353 {
354 __u1.release();
355 break;
356 }
357 }
358 sched_yield();
359 }
360}
361
362#ifndef _LIBCPP_HAS_NO_VARIADICS
363
364template <class _L0, class _L1, class ..._L2>
365void
366__lock_first(int __i, _L0& __l0, _L1& __l1, _L2& ...__l2)
367{
368 while (true)
369 {
370 switch (__i)
371 {
372 case 0:
373 {
374 unique_lock<_L0> __u0(__l0);
375 __i = try_lock(__l1, __l2...);
376 if (__i == -1)
377 {
378 __u0.release();
379 return;
380 }
381 }
382 ++__i;
383 sched_yield();
384 break;
385 case 1:
386 {
387 unique_lock<_L1> __u1(__l1);
388 __i = try_lock(__l2..., __l0);
389 if (__i == -1)
390 {
391 __u1.release();
392 return;
393 }
394 }
395 if (__i == sizeof...(_L2))
396 __i = 0;
397 else
398 __i += 2;
399 sched_yield();
400 break;
401 default:
402 __lock_first(__i - 2, __l2..., __l0, __l1);
403 return;
404 }
405 }
406}
407
408template <class _L0, class _L1, class ..._L2>
409inline
410void
411lock(_L0& __l0, _L1& __l1, _L2& ...__l2)
412{
413 __lock_first(0, __l0, __l1, __l2...);
414}
415
Howard Hinnant324bb032010-08-22 00:02:43 +0000416#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000417
418struct once_flag;
419
420#ifndef _LIBCPP_HAS_NO_VARIADICS
421
422template<class _Callable, class... _Args>
423 void call_once(once_flag&, _Callable&&, _Args&&...);
424
Howard Hinnant324bb032010-08-22 00:02:43 +0000425#else // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000426
427template<class _Callable>
428 void call_once(once_flag&, _Callable);
429
Howard Hinnant324bb032010-08-22 00:02:43 +0000430#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000431
432struct once_flag
433{
434 // constexpr
435 once_flag() {}
436
437private:
438 once_flag(const once_flag&); // = delete;
439 once_flag& operator=(const once_flag&); // = delete;
440
441 unsigned long __state_;
442
443#ifndef _LIBCPP_HAS_NO_VARIADICS
444 template<class _Callable, class... _Args>
445 friend
446 void call_once(once_flag&, _Callable&&, _Args&&...);
Howard Hinnant324bb032010-08-22 00:02:43 +0000447#else // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000448 template<class _Callable>
449 friend
450 void call_once(once_flag&, _Callable);
Howard Hinnant324bb032010-08-22 00:02:43 +0000451#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000452};
453
454template <class _F>
455class __call_once_param
456{
457 _F __f_;
458public:
Howard Hinnant73d21a42010-09-04 23:28:19 +0000459#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000460 explicit __call_once_param(_F&& __f) : __f_(_STD::move(__f)) {}
461#else
462 explicit __call_once_param(const _F& __f) : __f_(__f) {}
463#endif
464
465 void operator()()
466 {
467 __f_();
468 }
469};
470
471template <class _F>
472void
473__call_once_proxy(void* __vp)
474{
475 __call_once_param<_F>* __p = static_cast<__call_once_param<_F>*>(__vp);
476 (*__p)();
477}
478
479void __call_once(volatile unsigned long&, void*, void(*)(void*));
480
481#ifndef _LIBCPP_HAS_NO_VARIADICS
482
483template<class _Callable, class... _Args>
484inline _LIBCPP_INLINE_VISIBILITY
485void
486call_once(once_flag& __flag, _Callable&& __func, _Args&&... __args)
487{
488 if (__builtin_expect(__flag.__state_ , ~0ul) != ~0ul)
489 {
490 typedef decltype(std::bind(std::forward<_Callable>(__func),
491 std::forward<_Args>(__args)...)) _G;
492 __call_once_param<_G> __p(std::bind(std::forward<_Callable>(__func),
493 std::forward<_Args>(__args)...));
494 __call_once(__flag.__state_, &__p, &__call_once_proxy<_G>);
495 }
496}
497
Howard Hinnant324bb032010-08-22 00:02:43 +0000498#else // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000499
500template<class _Callable>
501inline _LIBCPP_INLINE_VISIBILITY
502void
503call_once(once_flag& __flag, _Callable __func)
504{
505 if (__flag.__state_ != ~0ul)
506 {
507 __call_once_param<_Callable> __p(__func);
508 __call_once(__flag.__state_, &__p, &__call_once_proxy<_Callable>);
509 }
510}
511
Howard Hinnant324bb032010-08-22 00:02:43 +0000512#endif // _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000513
514_LIBCPP_END_NAMESPACE_STD
515
516#endif // _LIBCPP_MUTEX