xref: /freebsd/contrib/llvm-project/libcxx/include/mutex (revision e1e636193db45630c7881246d25902e57c43d24e)
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 <__chrono/steady_clock.h>
191#include <__chrono/time_point.h>
192#include <__condition_variable/condition_variable.h>
193#include <__config>
194#include <__memory/shared_ptr.h>
195#include <__mutex/lock_guard.h>
196#include <__mutex/mutex.h>
197#include <__mutex/once_flag.h>
198#include <__mutex/tag_types.h>
199#include <__mutex/unique_lock.h>
200#include <__thread/id.h>
201#include <__threading_support>
202#include <__utility/forward.h>
203#include <cstddef>
204#include <limits>
205#ifndef _LIBCPP_CXX03_LANG
206#  include <tuple>
207#endif
208#include <version>
209
210#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
211#  pragma GCC system_header
212#endif
213
214_LIBCPP_PUSH_MACROS
215#include <__undef_macros>
216
217_LIBCPP_BEGIN_NAMESPACE_STD
218
219#ifndef _LIBCPP_HAS_NO_THREADS
220
221class _LIBCPP_EXPORTED_FROM_ABI recursive_mutex {
222  __libcpp_recursive_mutex_t __m_;
223
224public:
225  recursive_mutex();
226  ~recursive_mutex();
227
228  recursive_mutex(const recursive_mutex&)            = delete;
229  recursive_mutex& operator=(const recursive_mutex&) = delete;
230
231  void lock();
232  bool try_lock() _NOEXCEPT;
233  void unlock() _NOEXCEPT;
234
235  typedef __libcpp_recursive_mutex_t* native_handle_type;
236
237  _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__m_; }
238};
239
240class _LIBCPP_EXPORTED_FROM_ABI timed_mutex {
241  mutex __m_;
242  condition_variable __cv_;
243  bool __locked_;
244
245public:
246  timed_mutex();
247  ~timed_mutex();
248
249  timed_mutex(const timed_mutex&)            = delete;
250  timed_mutex& operator=(const timed_mutex&) = delete;
251
252public:
253  void lock();
254  bool try_lock() _NOEXCEPT;
255  template <class _Rep, class _Period>
256  _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) {
257    return try_lock_until(chrono::steady_clock::now() + __d);
258  }
259  template <class _Clock, class _Duration>
260  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
261  try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
262  void unlock() _NOEXCEPT;
263};
264
265template <class _Clock, class _Duration>
266bool timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) {
267  using namespace chrono;
268  unique_lock<mutex> __lk(__m_);
269  bool __no_timeout = _Clock::now() < __t;
270  while (__no_timeout && __locked_)
271    __no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout;
272  if (!__locked_) {
273    __locked_ = true;
274    return true;
275  }
276  return false;
277}
278
279class _LIBCPP_EXPORTED_FROM_ABI recursive_timed_mutex {
280  mutex __m_;
281  condition_variable __cv_;
282  size_t __count_;
283  __thread_id __id_;
284
285public:
286  recursive_timed_mutex();
287  ~recursive_timed_mutex();
288
289  recursive_timed_mutex(const recursive_timed_mutex&)            = delete;
290  recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
291
292  void lock();
293  bool try_lock() _NOEXCEPT;
294  template <class _Rep, class _Period>
295  _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) {
296    return try_lock_until(chrono::steady_clock::now() + __d);
297  }
298  template <class _Clock, class _Duration>
299  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
300  try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
301  void unlock() _NOEXCEPT;
302};
303
304template <class _Clock, class _Duration>
305bool recursive_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) {
306  using namespace chrono;
307  __thread_id __id = this_thread::get_id();
308  unique_lock<mutex> __lk(__m_);
309  if (__id == __id_) {
310    if (__count_ == numeric_limits<size_t>::max())
311      return false;
312    ++__count_;
313    return true;
314  }
315  bool __no_timeout = _Clock::now() < __t;
316  while (__no_timeout && __count_ != 0)
317    __no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout;
318  if (__count_ == 0) {
319    __count_ = 1;
320    __id_    = __id;
321    return true;
322  }
323  return false;
324}
325
326template <class _L0, class _L1>
327_LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1) {
328  unique_lock<_L0> __u0(__l0, try_to_lock_t());
329  if (__u0.owns_lock()) {
330    if (__l1.try_lock()) {
331      __u0.release();
332      return -1;
333    } else
334      return 1;
335  }
336  return 0;
337}
338
339#  ifndef _LIBCPP_CXX03_LANG
340
341template <class _L0, class _L1, class _L2, class... _L3>
342_LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
343  int __r = 0;
344  unique_lock<_L0> __u0(__l0, try_to_lock);
345  if (__u0.owns_lock()) {
346    __r = std::try_lock(__l1, __l2, __l3...);
347    if (__r == -1)
348      __u0.release();
349    else
350      ++__r;
351  }
352  return __r;
353}
354
355#  endif // _LIBCPP_CXX03_LANG
356
357template <class _L0, class _L1>
358_LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1) {
359  while (true) {
360    {
361      unique_lock<_L0> __u0(__l0);
362      if (__l1.try_lock()) {
363        __u0.release();
364        break;
365      }
366    }
367    __libcpp_thread_yield();
368    {
369      unique_lock<_L1> __u1(__l1);
370      if (__l0.try_lock()) {
371        __u1.release();
372        break;
373      }
374    }
375    __libcpp_thread_yield();
376  }
377}
378
379#  ifndef _LIBCPP_CXX03_LANG
380
381template <class _L0, class _L1, class _L2, class... _L3>
382void __lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
383  while (true) {
384    switch (__i) {
385    case 0: {
386      unique_lock<_L0> __u0(__l0);
387      __i = std::try_lock(__l1, __l2, __l3...);
388      if (__i == -1) {
389        __u0.release();
390        return;
391      }
392    }
393      ++__i;
394      __libcpp_thread_yield();
395      break;
396    case 1: {
397      unique_lock<_L1> __u1(__l1);
398      __i = std::try_lock(__l2, __l3..., __l0);
399      if (__i == -1) {
400        __u1.release();
401        return;
402      }
403    }
404      if (__i == sizeof...(_L3) + 1)
405        __i = 0;
406      else
407        __i += 2;
408      __libcpp_thread_yield();
409      break;
410    default:
411      std::__lock_first(__i - 2, __l2, __l3..., __l0, __l1);
412      return;
413    }
414  }
415}
416
417template <class _L0, class _L1, class _L2, class... _L3>
418inline _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
419  std::__lock_first(0, __l0, __l1, __l2, __l3...);
420}
421
422template <class _L0>
423inline _LIBCPP_HIDE_FROM_ABI void __unlock(_L0& __l0) {
424  __l0.unlock();
425}
426
427template <class _L0, class _L1>
428inline _LIBCPP_HIDE_FROM_ABI void __unlock(_L0& __l0, _L1& __l1) {
429  __l0.unlock();
430  __l1.unlock();
431}
432
433template <class _L0, class _L1, class _L2, class... _L3>
434inline _LIBCPP_HIDE_FROM_ABI void __unlock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
435  __l0.unlock();
436  __l1.unlock();
437  std::__unlock(__l2, __l3...);
438}
439
440#  endif // _LIBCPP_CXX03_LANG
441
442#  if _LIBCPP_STD_VER >= 17
443template <class... _Mutexes>
444class _LIBCPP_TEMPLATE_VIS scoped_lock;
445
446template <>
447class _LIBCPP_TEMPLATE_VIS scoped_lock<> {
448public:
449  explicit scoped_lock() {}
450  ~scoped_lock() = default;
451
452  _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(adopt_lock_t) {}
453
454  scoped_lock(scoped_lock const&)            = delete;
455  scoped_lock& operator=(scoped_lock const&) = delete;
456};
457
458template <class _Mutex>
459class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) scoped_lock<_Mutex> {
460public:
461  typedef _Mutex mutex_type;
462
463private:
464  mutex_type& __m_;
465
466public:
467  explicit scoped_lock(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m)) : __m_(__m) {
468    __m_.lock();
469  }
470
471  ~scoped_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) { __m_.unlock(); }
472
473  _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(adopt_lock_t, mutex_type& __m)
474      _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
475      : __m_(__m) {}
476
477  scoped_lock(scoped_lock const&)            = delete;
478  scoped_lock& operator=(scoped_lock const&) = delete;
479};
480
481template <class... _MArgs>
482class _LIBCPP_TEMPLATE_VIS scoped_lock {
483  static_assert(sizeof...(_MArgs) > 1, "At least 2 lock types required");
484  typedef tuple<_MArgs&...> _MutexTuple;
485
486public:
487  _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(_MArgs&... __margs) : __t_(__margs...) { std::lock(__margs...); }
488
489  _LIBCPP_HIDE_FROM_ABI scoped_lock(adopt_lock_t, _MArgs&... __margs) : __t_(__margs...) {}
490
491  _LIBCPP_HIDE_FROM_ABI ~scoped_lock() {
492    typedef typename __make_tuple_indices<sizeof...(_MArgs)>::type _Indices;
493    __unlock_unpack(_Indices{}, __t_);
494  }
495
496  scoped_lock(scoped_lock const&)            = delete;
497  scoped_lock& operator=(scoped_lock const&) = delete;
498
499private:
500  template <size_t... _Indx>
501  _LIBCPP_HIDE_FROM_ABI static void __unlock_unpack(__tuple_indices<_Indx...>, _MutexTuple& __mt) {
502    std::__unlock(std::get<_Indx>(__mt)...);
503  }
504
505  _MutexTuple __t_;
506};
507_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(scoped_lock);
508
509#  endif // _LIBCPP_STD_VER >= 17
510#endif   // !_LIBCPP_HAS_NO_THREADS
511
512_LIBCPP_END_NAMESPACE_STD
513
514_LIBCPP_POP_MACROS
515
516#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
517#  include <atomic>
518#  include <concepts>
519#  include <cstdlib>
520#  include <cstring>
521#  include <ctime>
522#  include <initializer_list>
523#  include <iosfwd>
524#  include <new>
525#  include <stdexcept>
526#  include <system_error>
527#  include <type_traits>
528#  include <typeinfo>
529#endif
530
531#endif // _LIBCPP_MUTEX
532