xref: /llvm-project-15.0.7/libcxx/include/mutex (revision faef447e)
1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef _LIBCPP_MUTEX
11#define _LIBCPP_MUTEX
12
13/*
14    mutex synopsis
15
16namespace std
17{
18
19class mutex
20{
21public:
22     constexpr mutex() noexcept;
23     ~mutex();
24
25    mutex(const mutex&) = delete;
26    mutex& operator=(const mutex&) = delete;
27
28    void lock();
29    bool try_lock();
30    void unlock();
31
32    typedef pthread_mutex_t* native_handle_type;
33    native_handle_type native_handle();
34};
35
36class recursive_mutex
37{
38public:
39     recursive_mutex();
40     ~recursive_mutex();
41
42    recursive_mutex(const recursive_mutex&) = delete;
43    recursive_mutex& operator=(const recursive_mutex&) = delete;
44
45    void lock();
46    bool try_lock() noexcept;
47    void unlock();
48
49    typedef pthread_mutex_t* native_handle_type;
50    native_handle_type native_handle();
51};
52
53class timed_mutex
54{
55public:
56     timed_mutex();
57     ~timed_mutex();
58
59    timed_mutex(const timed_mutex&) = delete;
60    timed_mutex& operator=(const timed_mutex&) = delete;
61
62    void lock();
63    bool try_lock();
64    template <class Rep, class Period>
65        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
66    template <class Clock, class Duration>
67        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
68    void unlock();
69};
70
71class recursive_timed_mutex
72{
73public:
74     recursive_timed_mutex();
75     ~recursive_timed_mutex();
76
77    recursive_timed_mutex(const recursive_timed_mutex&) = delete;
78    recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
79
80    void lock();
81    bool try_lock() noexcept;
82    template <class Rep, class Period>
83        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
84    template <class Clock, class Duration>
85        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
86    void unlock();
87};
88
89struct defer_lock_t { explicit defer_lock_t() = default; };
90struct try_to_lock_t { explicit try_to_lock_t() = default; };
91struct adopt_lock_t { explicit adopt_lock_t() = default; };
92
93inline constexpr defer_lock_t  defer_lock{};
94inline constexpr try_to_lock_t try_to_lock{};
95inline constexpr adopt_lock_t  adopt_lock{};
96
97template <class Mutex>
98class lock_guard
99{
100public:
101    typedef Mutex mutex_type;
102
103    explicit lock_guard(mutex_type& m);
104    lock_guard(mutex_type& m, adopt_lock_t);
105    ~lock_guard();
106
107    lock_guard(lock_guard const&) = delete;
108    lock_guard& operator=(lock_guard const&) = delete;
109};
110
111template <class... MutexTypes>
112class scoped_lock // C++17
113{
114public:
115    using mutex_type = Mutex;  // Only if sizeof...(MutexTypes) == 1
116
117    explicit scoped_lock(MutexTypes&... m);
118    scoped_lock(adopt_lock_t, MutexTypes&... m);
119    ~scoped_lock();
120    scoped_lock(scoped_lock const&) = delete;
121    scoped_lock& operator=(scoped_lock const&) = delete;
122private:
123    tuple<MutexTypes&...> pm; // exposition only
124};
125
126template <class Mutex>
127class unique_lock
128{
129public:
130    typedef Mutex mutex_type;
131    unique_lock() noexcept;
132    explicit unique_lock(mutex_type& m);
133    unique_lock(mutex_type& m, defer_lock_t) noexcept;
134    unique_lock(mutex_type& m, try_to_lock_t);
135    unique_lock(mutex_type& m, adopt_lock_t);
136    template <class Clock, class Duration>
137        unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
138    template <class Rep, class Period>
139        unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
140    ~unique_lock();
141
142    unique_lock(unique_lock const&) = delete;
143    unique_lock& operator=(unique_lock const&) = delete;
144
145    unique_lock(unique_lock&& u) noexcept;
146    unique_lock& operator=(unique_lock&& u) noexcept;
147
148    void lock();
149    bool try_lock();
150
151    template <class Rep, class Period>
152        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
153    template <class Clock, class Duration>
154        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
155
156    void unlock();
157
158    void swap(unique_lock& u) noexcept;
159    mutex_type* release() noexcept;
160
161    bool owns_lock() const noexcept;
162    explicit operator bool () const noexcept;
163    mutex_type* mutex() const noexcept;
164};
165
166template <class Mutex>
167  void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
168
169template <class L1, class L2, class... L3>
170  int try_lock(L1&, L2&, L3&...);
171template <class L1, class L2, class... L3>
172  void lock(L1&, L2&, L3&...);
173
174struct once_flag
175{
176    constexpr once_flag() noexcept;
177
178    once_flag(const once_flag&) = delete;
179    once_flag& operator=(const once_flag&) = delete;
180};
181
182template<class Callable, class ...Args>
183  void call_once(once_flag& flag, Callable&& func, Args&&... args);
184
185}  // std
186
187*/
188
189#include <__assert> // all public C++ headers provide the assertion handler
190#include <__config>
191#include <__mutex_base>
192#include <__threading_support>
193#include <__utility/forward.h>
194#include <cstdint>
195#include <functional> // TODO: Remove this include
196#include <memory>
197#ifndef _LIBCPP_CXX03_LANG
198# include <tuple>
199#endif
200#include <version>
201
202#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
203#  pragma GCC system_header
204#endif
205
206_LIBCPP_PUSH_MACROS
207#include <__undef_macros>
208
209
210_LIBCPP_BEGIN_NAMESPACE_STD
211
212#ifndef _LIBCPP_HAS_NO_THREADS
213
214class _LIBCPP_TYPE_VIS recursive_mutex
215{
216    __libcpp_recursive_mutex_t __m_;
217
218public:
219    recursive_mutex();
220    ~recursive_mutex();
221
222    recursive_mutex(const recursive_mutex&) = delete;
223    recursive_mutex& operator=(const recursive_mutex&) = delete;
224
225    void lock();
226    bool try_lock() _NOEXCEPT;
227    void unlock()  _NOEXCEPT;
228
229    typedef __libcpp_recursive_mutex_t* native_handle_type;
230
231    _LIBCPP_INLINE_VISIBILITY
232    native_handle_type native_handle() {return &__m_;}
233};
234
235class _LIBCPP_TYPE_VIS timed_mutex
236{
237    mutex              __m_;
238    condition_variable __cv_;
239    bool               __locked_;
240public:
241     timed_mutex();
242     ~timed_mutex();
243
244    timed_mutex(const timed_mutex&) = delete;
245    timed_mutex& operator=(const timed_mutex&) = delete;
246
247public:
248    void lock();
249    bool try_lock() _NOEXCEPT;
250    template <class _Rep, class _Period>
251        _LIBCPP_INLINE_VISIBILITY
252        bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
253            {return try_lock_until(chrono::steady_clock::now() + __d);}
254    template <class _Clock, class _Duration>
255        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
256        bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
257    void unlock() _NOEXCEPT;
258};
259
260template <class _Clock, class _Duration>
261bool
262timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
263{
264    using namespace chrono;
265    unique_lock<mutex> __lk(__m_);
266    bool no_timeout = _Clock::now() < __t;
267    while (no_timeout && __locked_)
268        no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout;
269    if (!__locked_)
270    {
271        __locked_ = true;
272        return true;
273    }
274    return false;
275}
276
277class _LIBCPP_TYPE_VIS recursive_timed_mutex
278{
279    mutex              __m_;
280    condition_variable __cv_;
281    size_t             __count_;
282    __thread_id        __id_;
283public:
284    recursive_timed_mutex();
285    ~recursive_timed_mutex();
286
287    recursive_timed_mutex(const recursive_timed_mutex&) = delete;
288    recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
289
290    void lock();
291    bool try_lock() _NOEXCEPT;
292    template <class _Rep, class _Period>
293        _LIBCPP_INLINE_VISIBILITY
294        bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
295            {return try_lock_until(chrono::steady_clock::now() + __d);}
296    template <class _Clock, class _Duration>
297        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
298        bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
299    void unlock() _NOEXCEPT;
300};
301
302template <class _Clock, class _Duration>
303bool
304recursive_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
305{
306    using namespace chrono;
307    __thread_id __id = this_thread::get_id();
308    unique_lock<mutex> lk(__m_);
309    if (__id == __id_)
310    {
311        if (__count_ == numeric_limits<size_t>::max())
312            return false;
313        ++__count_;
314        return true;
315    }
316    bool no_timeout = _Clock::now() < __t;
317    while (no_timeout && __count_ != 0)
318        no_timeout = __cv_.wait_until(lk, __t) == cv_status::no_timeout;
319    if (__count_ == 0)
320    {
321        __count_ = 1;
322        __id_ = __id;
323        return true;
324    }
325    return false;
326}
327
328template <class _L0, class _L1>
329int
330try_lock(_L0& __l0, _L1& __l1)
331{
332    unique_lock<_L0> __u0(__l0, try_to_lock);
333    if (__u0.owns_lock())
334    {
335        if (__l1.try_lock())
336        {
337            __u0.release();
338            return -1;
339        }
340        else
341            return 1;
342    }
343    return 0;
344}
345
346#ifndef _LIBCPP_CXX03_LANG
347
348template <class _L0, class _L1, class _L2, class... _L3>
349int
350try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3)
351{
352    int __r = 0;
353    unique_lock<_L0> __u0(__l0, try_to_lock);
354    if (__u0.owns_lock())
355    {
356        __r = try_lock(__l1, __l2, __l3...);
357        if (__r == -1)
358            __u0.release();
359        else
360            ++__r;
361    }
362    return __r;
363}
364
365#endif // _LIBCPP_CXX03_LANG
366
367template <class _L0, class _L1>
368void
369lock(_L0& __l0, _L1& __l1)
370{
371    while (true)
372    {
373        {
374            unique_lock<_L0> __u0(__l0);
375            if (__l1.try_lock())
376            {
377                __u0.release();
378                break;
379            }
380        }
381        __libcpp_thread_yield();
382        {
383            unique_lock<_L1> __u1(__l1);
384            if (__l0.try_lock())
385            {
386                __u1.release();
387                break;
388            }
389        }
390        __libcpp_thread_yield();
391    }
392}
393
394#ifndef _LIBCPP_CXX03_LANG
395
396template <class _L0, class _L1, class _L2, class ..._L3>
397void
398__lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
399{
400    while (true)
401    {
402        switch (__i)
403        {
404        case 0:
405            {
406                unique_lock<_L0> __u0(__l0);
407                __i = try_lock(__l1, __l2, __l3...);
408                if (__i == -1)
409                {
410                    __u0.release();
411                    return;
412                }
413            }
414            ++__i;
415            __libcpp_thread_yield();
416            break;
417        case 1:
418            {
419                unique_lock<_L1> __u1(__l1);
420                __i = try_lock(__l2, __l3..., __l0);
421                if (__i == -1)
422                {
423                    __u1.release();
424                    return;
425                }
426            }
427            if (__i == sizeof...(_L3) + 1)
428                __i = 0;
429            else
430                __i += 2;
431            __libcpp_thread_yield();
432            break;
433        default:
434            __lock_first(__i - 2, __l2, __l3..., __l0, __l1);
435            return;
436        }
437    }
438}
439
440template <class _L0, class _L1, class _L2, class ..._L3>
441inline _LIBCPP_INLINE_VISIBILITY
442void
443lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
444{
445    __lock_first(0, __l0, __l1, __l2, __l3...);
446}
447
448template <class _L0>
449inline _LIBCPP_INLINE_VISIBILITY
450void __unlock(_L0& __l0) {
451    __l0.unlock();
452}
453
454template <class _L0, class _L1>
455inline _LIBCPP_INLINE_VISIBILITY
456void __unlock(_L0& __l0, _L1& __l1) {
457    __l0.unlock();
458    __l1.unlock();
459}
460
461template <class _L0, class _L1, class _L2, class ..._L3>
462inline _LIBCPP_INLINE_VISIBILITY
463void __unlock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
464    __l0.unlock();
465    __l1.unlock();
466    _VSTD::__unlock(__l2, __l3...);
467}
468
469#endif // _LIBCPP_CXX03_LANG
470
471#if _LIBCPP_STD_VER > 14
472template <class ..._Mutexes>
473class _LIBCPP_TEMPLATE_VIS scoped_lock;
474
475template <>
476class _LIBCPP_TEMPLATE_VIS scoped_lock<> {
477public:
478    explicit scoped_lock() {}
479    ~scoped_lock() = default;
480
481    _LIBCPP_INLINE_VISIBILITY
482    explicit scoped_lock(adopt_lock_t) {}
483
484    scoped_lock(scoped_lock const&) = delete;
485    scoped_lock& operator=(scoped_lock const&) = delete;
486};
487
488template <class _Mutex>
489class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) scoped_lock<_Mutex> {
490public:
491    typedef _Mutex  mutex_type;
492private:
493    mutex_type& __m_;
494public:
495    explicit scoped_lock(mutex_type & __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m))
496        : __m_(__m) {__m_.lock();}
497
498    ~scoped_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();}
499
500    _LIBCPP_INLINE_VISIBILITY
501    explicit scoped_lock(adopt_lock_t, mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
502        : __m_(__m) {}
503
504    scoped_lock(scoped_lock const&) = delete;
505    scoped_lock& operator=(scoped_lock const&) = delete;
506};
507
508template <class ..._MArgs>
509class _LIBCPP_TEMPLATE_VIS scoped_lock
510{
511    static_assert(sizeof...(_MArgs) > 1, "At least 2 lock types required");
512    typedef tuple<_MArgs&...> _MutexTuple;
513
514public:
515    _LIBCPP_INLINE_VISIBILITY
516    explicit scoped_lock(_MArgs&... __margs)
517      : __t_(__margs...)
518    {
519        _VSTD::lock(__margs...);
520    }
521
522    _LIBCPP_INLINE_VISIBILITY
523    scoped_lock(adopt_lock_t, _MArgs&... __margs)
524        : __t_(__margs...)
525    {
526    }
527
528    _LIBCPP_INLINE_VISIBILITY
529    ~scoped_lock() {
530        typedef typename __make_tuple_indices<sizeof...(_MArgs)>::type _Indices;
531        __unlock_unpack(_Indices{}, __t_);
532    }
533
534    scoped_lock(scoped_lock const&) = delete;
535    scoped_lock& operator=(scoped_lock const&) = delete;
536
537private:
538    template <size_t ..._Indx>
539    _LIBCPP_INLINE_VISIBILITY
540    static void __unlock_unpack(__tuple_indices<_Indx...>, _MutexTuple& __mt) {
541        _VSTD::__unlock(_VSTD::get<_Indx>(__mt)...);
542    }
543
544    _MutexTuple __t_;
545};
546
547#endif // _LIBCPP_STD_VER > 14
548#endif // !_LIBCPP_HAS_NO_THREADS
549
550struct _LIBCPP_TEMPLATE_VIS once_flag;
551
552#ifndef _LIBCPP_CXX03_LANG
553
554template<class _Callable, class... _Args>
555_LIBCPP_INLINE_VISIBILITY
556void call_once(once_flag&, _Callable&&, _Args&&...);
557
558#else  // _LIBCPP_CXX03_LANG
559
560template<class _Callable>
561_LIBCPP_INLINE_VISIBILITY
562void call_once(once_flag&, _Callable&);
563
564template<class _Callable>
565_LIBCPP_INLINE_VISIBILITY
566void call_once(once_flag&, const _Callable&);
567
568#endif // _LIBCPP_CXX03_LANG
569
570struct _LIBCPP_TEMPLATE_VIS once_flag
571{
572    _LIBCPP_INLINE_VISIBILITY
573    _LIBCPP_CONSTEXPR
574        once_flag() _NOEXCEPT : __state_(0) {}
575    once_flag(const once_flag&) = delete;
576    once_flag& operator=(const once_flag&) = delete;
577
578#if defined(_LIBCPP_ABI_MICROSOFT)
579   typedef uintptr_t _State_type;
580#else
581   typedef unsigned long _State_type;
582#endif
583
584private:
585    _State_type __state_;
586
587#ifndef _LIBCPP_CXX03_LANG
588    template<class _Callable, class... _Args>
589    friend
590    void call_once(once_flag&, _Callable&&, _Args&&...);
591#else  // _LIBCPP_CXX03_LANG
592    template<class _Callable>
593    friend
594    void call_once(once_flag&, _Callable&);
595
596    template<class _Callable>
597    friend
598    void call_once(once_flag&, const _Callable&);
599#endif // _LIBCPP_CXX03_LANG
600};
601
602#ifndef _LIBCPP_CXX03_LANG
603
604template <class _Fp>
605class __call_once_param
606{
607    _Fp& __f_;
608public:
609    _LIBCPP_INLINE_VISIBILITY
610    explicit __call_once_param(_Fp& __f) : __f_(__f) {}
611
612    _LIBCPP_INLINE_VISIBILITY
613    void operator()()
614    {
615        typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 1>::type _Index;
616        __execute(_Index());
617    }
618
619private:
620    template <size_t ..._Indices>
621    _LIBCPP_INLINE_VISIBILITY
622    void __execute(__tuple_indices<_Indices...>)
623    {
624        _VSTD::__invoke(_VSTD::get<0>(_VSTD::move(__f_)), _VSTD::get<_Indices>(_VSTD::move(__f_))...);
625    }
626};
627
628#else
629
630template <class _Fp>
631class __call_once_param
632{
633    _Fp& __f_;
634public:
635    _LIBCPP_INLINE_VISIBILITY
636    explicit __call_once_param(_Fp& __f) : __f_(__f) {}
637
638    _LIBCPP_INLINE_VISIBILITY
639    void operator()()
640    {
641        __f_();
642    }
643};
644
645#endif
646
647template <class _Fp>
648void _LIBCPP_INLINE_VISIBILITY
649__call_once_proxy(void* __vp)
650{
651    __call_once_param<_Fp>* __p = static_cast<__call_once_param<_Fp>*>(__vp);
652    (*__p)();
653}
654
655_LIBCPP_FUNC_VIS void __call_once(volatile once_flag::_State_type&, void*,
656                                  void (*)(void*));
657
658#ifndef _LIBCPP_CXX03_LANG
659
660template<class _Callable, class... _Args>
661inline _LIBCPP_INLINE_VISIBILITY
662void
663call_once(once_flag& __flag, _Callable&& __func, _Args&&... __args)
664{
665    if (__libcpp_acquire_load(&__flag.__state_) != ~once_flag::_State_type(0))
666    {
667        typedef tuple<_Callable&&, _Args&&...> _Gp;
668        _Gp __f(_VSTD::forward<_Callable>(__func), _VSTD::forward<_Args>(__args)...);
669        __call_once_param<_Gp> __p(__f);
670        __call_once(__flag.__state_, &__p, &__call_once_proxy<_Gp>);
671    }
672}
673
674#else  // _LIBCPP_CXX03_LANG
675
676template<class _Callable>
677inline _LIBCPP_INLINE_VISIBILITY
678void
679call_once(once_flag& __flag, _Callable& __func)
680{
681    if (__libcpp_acquire_load(&__flag.__state_) != ~once_flag::_State_type(0))
682    {
683        __call_once_param<_Callable> __p(__func);
684        __call_once(__flag.__state_, &__p, &__call_once_proxy<_Callable>);
685    }
686}
687
688template<class _Callable>
689inline _LIBCPP_INLINE_VISIBILITY
690void
691call_once(once_flag& __flag, const _Callable& __func)
692{
693    if (__libcpp_acquire_load(&__flag.__state_) != ~once_flag::_State_type(0))
694    {
695        __call_once_param<const _Callable> __p(__func);
696        __call_once(__flag.__state_, &__p, &__call_once_proxy<const _Callable>);
697    }
698}
699
700#endif // _LIBCPP_CXX03_LANG
701
702_LIBCPP_END_NAMESPACE_STD
703
704_LIBCPP_POP_MACROS
705
706#endif // _LIBCPP_MUTEX
707