mutex revision 227825
1// -*- C++ -*-
2//===--------------------------- mutex ------------------------------------===//
3//
4//                     The LLVM Compiler Infrastructure
5//
6// This file is dual licensed under the MIT and the University of Illinois Open
7// Source Licenses. 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#ifndef _LIBCPP_HAS_NO_VARIADICS
179#include <tuple>
180#endif
181
182#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
183#pragma GCC system_header
184#endif
185
186_LIBCPP_BEGIN_NAMESPACE_STD
187
188class _LIBCPP_VISIBLE recursive_mutex
189{
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;
206    _LIBCPP_INLINE_VISIBILITY
207    native_handle_type native_handle() {return &__m_;}
208};
209
210class _LIBCPP_VISIBLE timed_mutex
211{
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>
227        _LIBCPP_INLINE_VISIBILITY
228        bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
229            {return try_lock_until(chrono::steady_clock::now() + __d);}
230    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
252class _LIBCPP_VISIBLE recursive_timed_mutex
253{
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>
270        _LIBCPP_INLINE_VISIBILITY
271        bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
272            {return try_lock_until(chrono::steady_clock::now() + __d);}
273    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
341#endif  // _LIBCPP_HAS_NO_VARIADICS
342
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
372template <class _L0, class _L1, class _L2, class ..._L3>
373void
374__lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
375{
376    while (true)
377    {
378        switch (__i)
379        {
380        case 0:
381            {
382                unique_lock<_L0> __u0(__l0);
383                __i = try_lock(__l1, __l2, __l3...);
384                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);
396                __i = try_lock(__l2, __l3..., __l0);
397                if (__i == -1)
398                {
399                    __u1.release();
400                    return;
401                }
402            }
403            if (__i == sizeof...(_L3) + 1)
404                __i = 0;
405            else
406                __i += 2;
407            sched_yield();
408            break;
409        default:
410            __lock_first(__i - 2, __l2, __l3..., __l0, __l1);
411            return;
412        }
413    }
414}
415
416template <class _L0, class _L1, class _L2, class ..._L3>
417inline _LIBCPP_INLINE_VISIBILITY
418void
419lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
420{
421    __lock_first(0, __l0, __l1, __l2, __l3...);
422}
423
424#endif  // _LIBCPP_HAS_NO_VARIADICS
425
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
433#else  // _LIBCPP_HAS_NO_VARIADICS
434
435template<class _Callable>
436  void call_once(once_flag&, _Callable);
437
438#endif  // _LIBCPP_HAS_NO_VARIADICS
439
440struct _LIBCPP_VISIBLE once_flag
441{
442    _LIBCPP_INLINE_VISIBILITY
443    // 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&&...);
456#else  // _LIBCPP_HAS_NO_VARIADICS
457    template<class _Callable>
458    friend
459    void call_once(once_flag&, _Callable);
460#endif  // _LIBCPP_HAS_NO_VARIADICS
461};
462
463#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
472    explicit __call_once_param(_F&& __f) : __f_(_VSTD::move(__f)) {}
473#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    {
490        __invoke(_VSTD::move(_VSTD::get<0>(__f_)), _VSTD::move(_VSTD::get<_Indices>(__f_))...);
491    }
492};
493
494#else
495
496template <class _F>
497class __call_once_param
498{
499    _F __f_;
500public:
501#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
502    _LIBCPP_INLINE_VISIBILITY
503    explicit __call_once_param(_F&& __f) : __f_(_VSTD::move(__f)) {}
504#else
505    _LIBCPP_INLINE_VISIBILITY
506    explicit __call_once_param(const _F& __f) : __f_(__f) {}
507#endif
508
509    _LIBCPP_INLINE_VISIBILITY
510    void operator()()
511    {
512        __f_();
513    }
514};
515
516#endif
517
518template <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    {
537        typedef tuple<typename decay<_Callable>::type, typename decay<_Args>::type...> _G;
538        __call_once_param<_G> __p(_G(__decay_copy(_VSTD::forward<_Callable>(__func)),
539                                __decay_copy(_VSTD::forward<_Args>(__args))...));
540        __call_once(__flag.__state_, &__p, &__call_once_proxy<_G>);
541    }
542}
543
544#else  // _LIBCPP_HAS_NO_VARIADICS
545
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
558#endif  // _LIBCPP_HAS_NO_VARIADICS
559
560_LIBCPP_END_NAMESPACE_STD
561
562#endif  // _LIBCPP_MUTEX
563