master
  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#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
190#  include <__cxx03/mutex>
191#else
192#  include <__chrono/steady_clock.h>
193#  include <__chrono/time_point.h>
194#  include <__condition_variable/condition_variable.h>
195#  include <__config>
196#  include <__mutex/lock_guard.h>
197#  include <__mutex/mutex.h>
198#  include <__mutex/once_flag.h>
199#  include <__mutex/tag_types.h>
200#  include <__mutex/unique_lock.h>
201#  include <__thread/id.h>
202#  include <__thread/support.h>
203#  include <__utility/forward.h>
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#  if _LIBCPP_HAS_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
260  template <class _Clock, class _Duration>
261  _LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) {
262    using namespace chrono;
263    unique_lock<mutex> __lk(__m_);
264    bool __no_timeout = _Clock::now() < __t;
265    while (__no_timeout && __locked_)
266      __no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout;
267    if (!__locked_) {
268      __locked_ = true;
269      return true;
270    }
271    return false;
272  }
273
274  void unlock() _NOEXCEPT;
275};
276
277class _LIBCPP_EXPORTED_FROM_ABI recursive_timed_mutex {
278  mutex __m_;
279  condition_variable __cv_;
280  size_t __count_;
281  __thread_id __id_;
282
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_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) {
294    return try_lock_until(chrono::steady_clock::now() + __d);
295  }
296
297  template <class _Clock, class _Duration>
298  _LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) {
299    using namespace chrono;
300    __thread_id __id = this_thread::get_id();
301    unique_lock<mutex> __lk(__m_);
302    if (__id == __id_) {
303      if (__count_ == numeric_limits<size_t>::max())
304        return false;
305      ++__count_;
306      return true;
307    }
308    bool __no_timeout = _Clock::now() < __t;
309    while (__no_timeout && __count_ != 0)
310      __no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout;
311    if (__count_ == 0) {
312      __count_ = 1;
313      __id_    = __id;
314      return true;
315    }
316    return false;
317  }
318
319  void unlock() _NOEXCEPT;
320};
321
322template <class _L0, class _L1>
323_LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1) {
324  unique_lock<_L0> __u0(__l0, try_to_lock_t());
325  if (__u0.owns_lock()) {
326    if (__l1.try_lock()) {
327      __u0.release();
328      return -1;
329    } else
330      return 1;
331  }
332  return 0;
333}
334
335#    ifndef _LIBCPP_CXX03_LANG
336
337template <class _L0, class _L1, class _L2, class... _L3>
338_LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
339  int __r = 0;
340  unique_lock<_L0> __u0(__l0, try_to_lock);
341  if (__u0.owns_lock()) {
342    __r = std::try_lock(__l1, __l2, __l3...);
343    if (__r == -1)
344      __u0.release();
345    else
346      ++__r;
347  }
348  return __r;
349}
350
351#    endif // _LIBCPP_CXX03_LANG
352
353template <class _L0, class _L1>
354_LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1) {
355  while (true) {
356    {
357      unique_lock<_L0> __u0(__l0);
358      if (__l1.try_lock()) {
359        __u0.release();
360        break;
361      }
362    }
363    __libcpp_thread_yield();
364    {
365      unique_lock<_L1> __u1(__l1);
366      if (__l0.try_lock()) {
367        __u1.release();
368        break;
369      }
370    }
371    __libcpp_thread_yield();
372  }
373}
374
375#    ifndef _LIBCPP_CXX03_LANG
376
377template <class _L0, class _L1, class _L2, class... _L3>
378void __lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
379  while (true) {
380    switch (__i) {
381    case 0: {
382      unique_lock<_L0> __u0(__l0);
383      __i = std::try_lock(__l1, __l2, __l3...);
384      if (__i == -1) {
385        __u0.release();
386        return;
387      }
388    }
389      ++__i;
390      __libcpp_thread_yield();
391      break;
392    case 1: {
393      unique_lock<_L1> __u1(__l1);
394      __i = std::try_lock(__l2, __l3..., __l0);
395      if (__i == -1) {
396        __u1.release();
397        return;
398      }
399    }
400      if (__i == sizeof...(_L3) + 1)
401        __i = 0;
402      else
403        __i += 2;
404      __libcpp_thread_yield();
405      break;
406    default:
407      std::__lock_first(__i - 2, __l2, __l3..., __l0, __l1);
408      return;
409    }
410  }
411}
412
413template <class _L0, class _L1, class _L2, class... _L3>
414inline _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
415  std::__lock_first(0, __l0, __l1, __l2, __l3...);
416}
417
418#    endif // _LIBCPP_CXX03_LANG
419
420#    if _LIBCPP_STD_VER >= 17
421template <class... _Mutexes>
422class scoped_lock;
423
424template <>
425class scoped_lock<> {
426public:
427  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock() {}
428  ~scoped_lock() = default;
429
430  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(adopt_lock_t) {}
431
432  scoped_lock(scoped_lock const&)            = delete;
433  scoped_lock& operator=(scoped_lock const&) = delete;
434};
435
436template <class _Mutex>
437class _LIBCPP_SCOPED_LOCKABLE scoped_lock<_Mutex> {
438public:
439  typedef _Mutex mutex_type;
440
441private:
442  mutex_type& __m_;
443
444public:
445  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(mutex_type& __m) _LIBCPP_ACQUIRE_CAPABILITY(__m)
446      : __m_(__m) {
447    __m_.lock();
448  }
449
450  _LIBCPP_RELEASE_CAPABILITY _LIBCPP_HIDE_FROM_ABI ~scoped_lock() { __m_.unlock(); }
451
452  [[nodiscard]]
453  _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(adopt_lock_t, mutex_type& __m) _LIBCPP_REQUIRES_CAPABILITY(__m)
454      : __m_(__m) {}
455
456  scoped_lock(scoped_lock const&)            = delete;
457  scoped_lock& operator=(scoped_lock const&) = delete;
458};
459
460template <class... _MArgs>
461class scoped_lock {
462  static_assert(sizeof...(_MArgs) > 1, "At least 2 lock types required");
463  typedef tuple<_MArgs&...> _MutexTuple;
464
465public:
466  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(_MArgs&... __margs) : __t_(__margs...) {
467    std::lock(__margs...);
468  }
469
470  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI scoped_lock(adopt_lock_t, _MArgs&... __margs) : __t_(__margs...) {}
471
472  _LIBCPP_HIDE_FROM_ABI ~scoped_lock() {
473    typedef typename __make_tuple_indices<sizeof...(_MArgs)>::type _Indices;
474    __unlock_unpack(_Indices{}, __t_);
475  }
476
477  scoped_lock(scoped_lock const&)            = delete;
478  scoped_lock& operator=(scoped_lock const&) = delete;
479
480private:
481  template <size_t... _Indx>
482  _LIBCPP_HIDE_FROM_ABI static void __unlock_unpack(__tuple_indices<_Indx...>, _MutexTuple& __mt) {
483    (std::get<_Indx>(__mt).unlock(), ...);
484  }
485
486  _MutexTuple __t_;
487};
488_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(scoped_lock);
489
490#    endif // _LIBCPP_STD_VER >= 17
491#  endif   // _LIBCPP_HAS_THREADS
492
493_LIBCPP_END_NAMESPACE_STD
494
495_LIBCPP_POP_MACROS
496
497#  if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
498#    include <atomic>
499#    include <concepts>
500#    include <cstdlib>
501#    include <cstring>
502#    include <ctime>
503#    include <initializer_list>
504#    include <iosfwd>
505#    include <new>
506#    include <optional>
507#    include <stdexcept>
508#    include <system_error>
509#    include <type_traits>
510#    include <typeinfo>
511#  endif
512#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
513
514#endif // _LIBCPP_MUTEX