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_SHARED_MUTEX
 11#define _LIBCPP_SHARED_MUTEX
 12
 13/*
 14    shared_mutex synopsis
 15
 16// C++1y
 17
 18namespace std
 19{
 20
 21class shared_mutex      // C++17
 22{
 23public:
 24    shared_mutex();
 25    ~shared_mutex();
 26
 27    shared_mutex(const shared_mutex&) = delete;
 28    shared_mutex& operator=(const shared_mutex&) = delete;
 29
 30    // Exclusive ownership
 31    void lock(); // blocking
 32    bool try_lock();
 33    void unlock();
 34
 35    // Shared ownership
 36    void lock_shared(); // blocking
 37    bool try_lock_shared();
 38    void unlock_shared();
 39
 40    typedef implementation-defined native_handle_type; // See 30.2.3
 41    native_handle_type native_handle(); // See 30.2.3
 42};
 43
 44class shared_timed_mutex
 45{
 46public:
 47    shared_timed_mutex();
 48    ~shared_timed_mutex();
 49
 50    shared_timed_mutex(const shared_timed_mutex&) = delete;
 51    shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
 52
 53    // Exclusive ownership
 54    void lock(); // blocking
 55    bool try_lock();
 56    template <class Rep, class Period>
 57        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
 58    template <class Clock, class Duration>
 59        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
 60    void unlock();
 61
 62    // Shared ownership
 63    void lock_shared(); // blocking
 64    bool try_lock_shared();
 65    template <class Rep, class Period>
 66        bool
 67        try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
 68    template <class Clock, class Duration>
 69        bool
 70        try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
 71    void unlock_shared();
 72};
 73
 74template <class Mutex>
 75class shared_lock
 76{
 77public:
 78    typedef Mutex mutex_type;
 79
 80    // Shared locking
 81    shared_lock() noexcept;
 82    explicit shared_lock(mutex_type& m); // blocking
 83    shared_lock(mutex_type& m, defer_lock_t) noexcept;
 84    shared_lock(mutex_type& m, try_to_lock_t);
 85    shared_lock(mutex_type& m, adopt_lock_t);
 86    template <class Clock, class Duration>
 87        shared_lock(mutex_type& m,
 88                    const chrono::time_point<Clock, Duration>& abs_time);
 89    template <class Rep, class Period>
 90        shared_lock(mutex_type& m,
 91                    const chrono::duration<Rep, Period>& rel_time);
 92    ~shared_lock();
 93
 94    shared_lock(shared_lock const&) = delete;
 95    shared_lock& operator=(shared_lock const&) = delete;
 96
 97    shared_lock(shared_lock&& u) noexcept;
 98    shared_lock& operator=(shared_lock&& u) noexcept;
 99
100    void lock(); // blocking
101    bool try_lock();
102    template <class Rep, class Period>
103        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
104    template <class Clock, class Duration>
105        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
106    void unlock();
107
108    // Setters
109    void swap(shared_lock& u) noexcept;
110    mutex_type* release() noexcept;
111
112    // Getters
113    bool owns_lock() const noexcept;
114    explicit operator bool () const noexcept;
115    mutex_type* mutex() const noexcept;
116};
117
118template <class Mutex>
119    void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
120
121}  // std
122
123*/
124
125#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
126#  include <__cxx03/__config>
127#else
128#  include <__config>
129
130#  if _LIBCPP_HAS_THREADS
131
132#    include <__chrono/duration.h>
133#    include <__chrono/steady_clock.h>
134#    include <__chrono/time_point.h>
135#    include <__condition_variable/condition_variable.h>
136#    include <__memory/addressof.h>
137#    include <__mutex/mutex.h>
138#    include <__mutex/tag_types.h>
139#    include <__mutex/unique_lock.h>
140#    include <__system_error/throw_system_error.h>
141#    include <__utility/swap.h>
142#    include <cerrno>
143#    include <version>
144
145_LIBCPP_PUSH_MACROS
146#    include <__undef_macros>
147
148#    if _LIBCPP_STD_VER >= 14
149
150#      if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
151#        pragma GCC system_header
152#      endif
153
154_LIBCPP_BEGIN_NAMESPACE_STD
155
156struct _LIBCPP_EXPORTED_FROM_ABI __shared_mutex_base {
157  mutex __mut_;
158  condition_variable __gate1_;
159  condition_variable __gate2_;
160  unsigned __state_;
161
162  static const unsigned __write_entered_ = 1U << (sizeof(unsigned) * __CHAR_BIT__ - 1);
163  static const unsigned __n_readers_     = ~__write_entered_;
164
165  __shared_mutex_base();
166  _LIBCPP_HIDE_FROM_ABI ~__shared_mutex_base() = default;
167
168  __shared_mutex_base(const __shared_mutex_base&)            = delete;
169  __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
170
171  // Exclusive ownership
172  void lock(); // blocking
173  bool try_lock();
174  void unlock();
175
176  // Shared ownership
177  void lock_shared(); // blocking
178  bool try_lock_shared();
179  void unlock_shared();
180
181  //     typedef implementation-defined native_handle_type; // See 30.2.3
182  //     native_handle_type native_handle(); // See 30.2.3
183};
184
185#      if _LIBCPP_STD_VER >= 17
186class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CAPABILITY("shared_mutex") shared_mutex {
187  __shared_mutex_base __base_;
188
189public:
190  _LIBCPP_HIDE_FROM_ABI shared_mutex() : __base_() {}
191  _LIBCPP_HIDE_FROM_ABI ~shared_mutex() = default;
192
193  shared_mutex(const shared_mutex&)            = delete;
194  shared_mutex& operator=(const shared_mutex&) = delete;
195
196  // Exclusive ownership
197  _LIBCPP_ACQUIRE_CAPABILITY() _LIBCPP_HIDE_FROM_ABI void lock() { return __base_.lock(); }
198  _LIBCPP_TRY_ACQUIRE_CAPABILITY(true) _LIBCPP_HIDE_FROM_ABI bool try_lock() { return __base_.try_lock(); }
199  _LIBCPP_RELEASE_CAPABILITY _LIBCPP_HIDE_FROM_ABI void unlock() { return __base_.unlock(); }
200
201  // Shared ownership
202  _LIBCPP_ACQUIRE_SHARED_CAPABILITY _LIBCPP_HIDE_FROM_ABI void lock_shared() { return __base_.lock_shared(); }
203  _LIBCPP_TRY_ACQUIRE_SHARED_CAPABILITY(true) _LIBCPP_HIDE_FROM_ABI bool try_lock_shared() {
204    return __base_.try_lock_shared();
205  }
206  _LIBCPP_RELEASE_SHARED_CAPABILITY _LIBCPP_HIDE_FROM_ABI void unlock_shared() { return __base_.unlock_shared(); }
207
208  //     typedef __shared_mutex_base::native_handle_type native_handle_type;
209  //     _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return __base::unlock_shared(); }
210};
211#      endif
212
213class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_CAPABILITY("shared_timed_mutex") shared_timed_mutex {
214  __shared_mutex_base __base_;
215
216public:
217  shared_timed_mutex();
218  _LIBCPP_HIDE_FROM_ABI ~shared_timed_mutex() = default;
219
220  shared_timed_mutex(const shared_timed_mutex&)            = delete;
221  shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
222
223  // Exclusive ownership
224  void lock() _LIBCPP_ACQUIRE_CAPABILITY();
225  _LIBCPP_TRY_ACQUIRE_CAPABILITY(true) bool try_lock();
226  template <class _Rep, class _Period>
227  _LIBCPP_TRY_ACQUIRE_CAPABILITY(true) _LIBCPP_HIDE_FROM_ABI bool
228  try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time) {
229    return try_lock_until(chrono::steady_clock::now() + __rel_time);
230  }
231
232  template <class _Clock, class _Duration>
233  _LIBCPP_TRY_ACQUIRE_CAPABILITY(true) _LIBCPP_HIDE_FROM_ABI bool
234  try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time) {
235    unique_lock<mutex> __lk(__base_.__mut_);
236    if (__base_.__state_ & __base_.__write_entered_) {
237      while (true) {
238        cv_status __status = __base_.__gate1_.wait_until(__lk, __abs_time);
239        if ((__base_.__state_ & __base_.__write_entered_) == 0)
240          break;
241        if (__status == cv_status::timeout)
242          return false;
243      }
244    }
245    __base_.__state_ |= __base_.__write_entered_;
246    if (__base_.__state_ & __base_.__n_readers_) {
247      while (true) {
248        cv_status __status = __base_.__gate2_.wait_until(__lk, __abs_time);
249        if ((__base_.__state_ & __base_.__n_readers_) == 0)
250          break;
251        if (__status == cv_status::timeout) {
252          __base_.__state_ &= ~__base_.__write_entered_;
253          __base_.__gate1_.notify_all();
254          return false;
255        }
256      }
257    }
258    return true;
259  }
260
261  _LIBCPP_RELEASE_CAPABILITY void unlock();
262
263  // Shared ownership
264  _LIBCPP_ACQUIRE_SHARED_CAPABILITY void lock_shared();
265  _LIBCPP_TRY_ACQUIRE_SHARED_CAPABILITY(true) bool try_lock_shared();
266  template <class _Rep, class _Period>
267  _LIBCPP_TRY_ACQUIRE_SHARED_CAPABILITY(true) _LIBCPP_HIDE_FROM_ABI bool
268  try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time) {
269    return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
270  }
271
272  template <class _Clock, class _Duration>
273  _LIBCPP_TRY_ACQUIRE_SHARED_CAPABILITY(true) _LIBCPP_HIDE_FROM_ABI bool
274  try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time) {
275    unique_lock<mutex> __lk(__base_.__mut_);
276    if ((__base_.__state_ & __base_.__write_entered_) ||
277        (__base_.__state_ & __base_.__n_readers_) == __base_.__n_readers_) {
278      while (true) {
279        cv_status __status = __base_.__gate1_.wait_until(__lk, __abs_time);
280        if ((__base_.__state_ & __base_.__write_entered_) == 0 &&
281            (__base_.__state_ & __base_.__n_readers_) < __base_.__n_readers_)
282          break;
283        if (__status == cv_status::timeout)
284          return false;
285      }
286    }
287    unsigned __num_readers = (__base_.__state_ & __base_.__n_readers_) + 1;
288    __base_.__state_ &= ~__base_.__n_readers_;
289    __base_.__state_ |= __num_readers;
290    return true;
291  }
292
293  _LIBCPP_RELEASE_SHARED_CAPABILITY void unlock_shared();
294};
295
296template <class _Mutex>
297class shared_lock {
298public:
299  typedef _Mutex mutex_type;
300
301private:
302  mutex_type* __m_;
303  bool __owns_;
304
305public:
306  _LIBCPP_HIDE_FROM_ABI shared_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
307
308  _LIBCPP_HIDE_FROM_ABI explicit shared_lock(mutex_type& __m) : __m_(std::addressof(__m)), __owns_(true) {
309    __m_->lock_shared();
310  }
311
312  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
313      : __m_(std::addressof(__m)),
314        __owns_(false) {}
315
316  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, try_to_lock_t)
317      : __m_(std::addressof(__m)), __owns_(__m.try_lock_shared()) {}
318
319  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, adopt_lock_t) : __m_(std::addressof(__m)), __owns_(true) {}
320
321  template <class _Clock, class _Duration>
322  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __abs_time)
323      : __m_(std::addressof(__m)), __owns_(__m.try_lock_shared_until(__abs_time)) {}
324
325  template <class _Rep, class _Period>
326  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __rel_time)
327      : __m_(std::addressof(__m)), __owns_(__m.try_lock_shared_for(__rel_time)) {}
328
329  _LIBCPP_HIDE_FROM_ABI ~shared_lock() {
330    if (__owns_)
331      __m_->unlock_shared();
332  }
333
334  shared_lock(shared_lock const&)            = delete;
335  shared_lock& operator=(shared_lock const&) = delete;
336
337  _LIBCPP_HIDE_FROM_ABI shared_lock(shared_lock&& __u) _NOEXCEPT : __m_(__u.__m_), __owns_(__u.__owns_) {
338    __u.__m_    = nullptr;
339    __u.__owns_ = false;
340  }
341
342  _LIBCPP_HIDE_FROM_ABI shared_lock& operator=(shared_lock&& __u) _NOEXCEPT {
343    if (__owns_)
344      __m_->unlock_shared();
345    __m_        = nullptr;
346    __owns_     = false;
347    __m_        = __u.__m_;
348    __owns_     = __u.__owns_;
349    __u.__m_    = nullptr;
350    __u.__owns_ = false;
351    return *this;
352  }
353
354  _LIBCPP_HIDE_FROM_ABI void lock();
355  _LIBCPP_HIDE_FROM_ABI bool try_lock();
356  template <class _Rep, class _Period>
357  _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time);
358  template <class _Clock, class _Duration>
359  _LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
360  _LIBCPP_HIDE_FROM_ABI void unlock();
361
362  // Setters
363  _LIBCPP_HIDE_FROM_ABI void swap(shared_lock& __u) _NOEXCEPT {
364    std::swap(__m_, __u.__m_);
365    std::swap(__owns_, __u.__owns_);
366  }
367
368  _LIBCPP_HIDE_FROM_ABI mutex_type* release() _NOEXCEPT {
369    mutex_type* __m = __m_;
370    __m_            = nullptr;
371    __owns_         = false;
372    return __m;
373  }
374
375  // Getters
376  _LIBCPP_HIDE_FROM_ABI bool owns_lock() const _NOEXCEPT { return __owns_; }
377
378  _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __owns_; }
379
380  _LIBCPP_HIDE_FROM_ABI mutex_type* mutex() const _NOEXCEPT { return __m_; }
381};
382_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(shared_lock);
383
384template <class _Mutex>
385void shared_lock<_Mutex>::lock() {
386  if (__m_ == nullptr)
387    std::__throw_system_error(EPERM, "shared_lock::lock: references null mutex");
388  if (__owns_)
389    std::__throw_system_error(EDEADLK, "shared_lock::lock: already locked");
390  __m_->lock_shared();
391  __owns_ = true;
392}
393
394template <class _Mutex>
395bool shared_lock<_Mutex>::try_lock() {
396  if (__m_ == nullptr)
397    std::__throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
398  if (__owns_)
399    std::__throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
400  __owns_ = __m_->try_lock_shared();
401  return __owns_;
402}
403
404template <class _Mutex>
405template <class _Rep, class _Period>
406bool shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d) {
407  if (__m_ == nullptr)
408    std::__throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
409  if (__owns_)
410    std::__throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
411  __owns_ = __m_->try_lock_shared_for(__d);
412  return __owns_;
413}
414
415template <class _Mutex>
416template <class _Clock, class _Duration>
417bool shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) {
418  if (__m_ == nullptr)
419    std::__throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
420  if (__owns_)
421    std::__throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
422  __owns_ = __m_->try_lock_shared_until(__t);
423  return __owns_;
424}
425
426template <class _Mutex>
427void shared_lock<_Mutex>::unlock() {
428  if (!__owns_)
429    std::__throw_system_error(EPERM, "shared_lock::unlock: not locked");
430  __m_->unlock_shared();
431  __owns_ = false;
432}
433
434template <class _Mutex>
435inline _LIBCPP_HIDE_FROM_ABI void swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT {
436  __x.swap(__y);
437}
438
439_LIBCPP_END_NAMESPACE_STD
440
441#    endif // _LIBCPP_STD_VER >= 14
442
443_LIBCPP_POP_MACROS
444
445#  endif // _LIBCPP_HAS_THREADS
446
447#  if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
448#    include <optional>
449#    include <system_error>
450#  endif
451#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
452
453#endif // _LIBCPP_SHARED_MUTEX