xref: /llvm-project-15.0.7/libcxx/include/mutex (revision a462f5cc)
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
179#pragma GCC system_header
180
181_LIBCPP_BEGIN_NAMESPACE_STD
182
183class _LIBCPP_VISIBLE 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    _LIBCPP_INLINE_VISIBILITY
202    native_handle_type native_handle() {return &__m_;}
203};
204
205class _LIBCPP_VISIBLE timed_mutex
206{
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>
222        _LIBCPP_INLINE_VISIBILITY
223        bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
224            {return try_lock_until(chrono::steady_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
247class _LIBCPP_VISIBLE recursive_timed_mutex
248{
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>
265        _LIBCPP_INLINE_VISIBILITY
266        bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
267            {return try_lock_until(chrono::steady_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
336#endif  // _LIBCPP_HAS_NO_VARIADICS
337
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, class ..._L3>
368void
369__lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
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, __l3...);
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, __l3..., __l0);
392                if (__i == -1)
393                {
394                    __u1.release();
395                    return;
396                }
397            }
398            if (__i == sizeof...(_L3) + 1)
399                __i = 0;
400            else
401                __i += 2;
402            sched_yield();
403            break;
404        default:
405            __lock_first(__i - 2, __l2, __l3..., __l0, __l1);
406            return;
407        }
408    }
409}
410
411template <class _L0, class _L1, class _L2, class ..._L3>
412inline _LIBCPP_INLINE_VISIBILITY
413void
414lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
415{
416    __lock_first(0, __l0, __l1, __l2, __l3...);
417}
418
419#endif  // _LIBCPP_HAS_NO_VARIADICS
420
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
428#else  // _LIBCPP_HAS_NO_VARIADICS
429
430template<class _Callable>
431  void call_once(once_flag&, _Callable);
432
433#endif  // _LIBCPP_HAS_NO_VARIADICS
434
435struct _LIBCPP_VISIBLE once_flag
436{
437    _LIBCPP_INLINE_VISIBILITY
438    // 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&&...);
451#else  // _LIBCPP_HAS_NO_VARIADICS
452    template<class _Callable>
453    friend
454    void call_once(once_flag&, _Callable);
455#endif  // _LIBCPP_HAS_NO_VARIADICS
456};
457
458template <class _F>
459class __call_once_param
460{
461    _F __f_;
462public:
463#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
464    _LIBCPP_INLINE_VISIBILITY
465    explicit __call_once_param(_F&& __f) : __f_(_STD::move(__f)) {}
466#else
467    _LIBCPP_INLINE_VISIBILITY
468    explicit __call_once_param(const _F& __f) : __f_(__f) {}
469#endif
470
471    _LIBCPP_INLINE_VISIBILITY
472    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
505#else  // _LIBCPP_HAS_NO_VARIADICS
506
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
519#endif  // _LIBCPP_HAS_NO_VARIADICS
520
521_LIBCPP_END_NAMESPACE_STD
522
523#endif  // _LIBCPP_MUTEX
524