2 //===------------------------ shared_mutex --------------------------------===//
4 // The LLVM Compiler Infrastructure
6 // This file is dual licensed under the MIT and the University of Illinois Open
7 // Source Licenses. See LICENSE.TXT for details.
9 //===----------------------------------------------------------------------===//
11 #ifndef _LIBCPP_SHARED_MUTEX
12 #define _LIBCPP_SHARED_MUTEX
28 shared_mutex(const shared_mutex&) = delete;
29 shared_mutex& operator=(const shared_mutex&) = delete;
31 // Exclusive ownership
32 void lock(); // blocking
34 template <class Rep, class Period>
35 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
36 template <class Clock, class Duration>
37 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
41 void lock_shared(); // blocking
42 bool try_lock_shared();
43 template <class Rep, class Period>
45 try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
46 template <class Clock, class Duration>
48 try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
52 template <class Mutex>
56 typedef Mutex mutex_type;
59 shared_lock() noexcept;
60 explicit shared_lock(mutex_type& m); // blocking
61 shared_lock(mutex_type& m, defer_lock_t) noexcept;
62 shared_lock(mutex_type& m, try_to_lock_t);
63 shared_lock(mutex_type& m, adopt_lock_t);
64 template <class Clock, class Duration>
65 shared_lock(mutex_type& m,
66 const chrono::time_point<Clock, Duration>& abs_time);
67 template <class Rep, class Period>
68 shared_lock(mutex_type& m,
69 const chrono::duration<Rep, Period>& rel_time);
72 shared_lock(shared_lock const&) = delete;
73 shared_lock& operator=(shared_lock const&) = delete;
75 shared_lock(shared_lock&& u) noexcept;
76 shared_lock& operator=(shared_lock&& u) noexcept;
78 void lock(); // blocking
80 template <class Rep, class Period>
81 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
82 template <class Clock, class Duration>
83 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
87 void swap(shared_lock& u) noexcept;
88 mutex_type* release() noexcept;
91 bool owns_lock() const noexcept;
92 explicit operator bool () const noexcept;
93 mutex_type* mutex() const noexcept;
96 template <class Mutex>
97 void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
105 #if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_SHARED_MUTEX)
107 #include <__mutex_base>
109 #include <__undef_min_max>
111 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
112 #pragma GCC system_header
115 _LIBCPP_BEGIN_NAMESPACE_STD
117 class _LIBCPP_TYPE_VIS shared_mutex
120 condition_variable __gate1_;
121 condition_variable __gate2_;
124 static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
125 static const unsigned __n_readers_ = ~__write_entered_;
128 _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default;
130 shared_mutex(const shared_mutex&) = delete;
131 shared_mutex& operator=(const shared_mutex&) = delete;
133 // Exclusive ownership
136 template <class _Rep, class _Period>
137 _LIBCPP_INLINE_VISIBILITY
139 try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
141 return try_lock_until(chrono::steady_clock::now() + __rel_time);
143 template <class _Clock, class _Duration>
145 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
150 bool try_lock_shared();
151 template <class _Rep, class _Period>
152 _LIBCPP_INLINE_VISIBILITY
154 try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
156 return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
158 template <class _Clock, class _Duration>
160 try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
161 void unlock_shared();
164 template <class _Clock, class _Duration>
166 shared_mutex::try_lock_until(
167 const chrono::time_point<_Clock, _Duration>& __abs_time)
169 unique_lock<mutex> __lk(__mut_);
170 if (__state_ & __write_entered_)
174 cv_status __status = __gate1_.wait_until(__lk, __abs_time);
175 if ((__state_ & __write_entered_) == 0)
177 if (__status == cv_status::timeout)
181 __state_ |= __write_entered_;
182 if (__state_ & __n_readers_)
186 cv_status __status = __gate2_.wait_until(__lk, __abs_time);
187 if ((__state_ & __n_readers_) == 0)
189 if (__status == cv_status::timeout)
191 __state_ &= ~__write_entered_;
199 template <class _Clock, class _Duration>
201 shared_mutex::try_lock_shared_until(
202 const chrono::time_point<_Clock, _Duration>& __abs_time)
204 unique_lock<mutex> __lk(__mut_);
205 if ((__state_ & __write_entered_) || (__state_ & __n_readers_) == __n_readers_)
209 cv_status status = __gate1_.wait_until(__lk, __abs_time);
210 if ((__state_ & __write_entered_) == 0 &&
211 (__state_ & __n_readers_) < __n_readers_)
213 if (status == cv_status::timeout)
217 unsigned __num_readers = (__state_ & __n_readers_) + 1;
218 __state_ &= ~__n_readers_;
219 __state_ |= __num_readers;
223 template <class _Mutex>
227 typedef _Mutex mutex_type;
234 _LIBCPP_INLINE_VISIBILITY
235 shared_lock() noexcept
240 _LIBCPP_INLINE_VISIBILITY
241 explicit shared_lock(mutex_type& __m)
244 {__m_->lock_shared();}
246 _LIBCPP_INLINE_VISIBILITY
247 shared_lock(mutex_type& __m, defer_lock_t) noexcept
252 _LIBCPP_INLINE_VISIBILITY
253 shared_lock(mutex_type& __m, try_to_lock_t)
255 __owns_(__m.try_lock_shared())
258 _LIBCPP_INLINE_VISIBILITY
259 shared_lock(mutex_type& __m, adopt_lock_t)
264 template <class _Clock, class _Duration>
265 _LIBCPP_INLINE_VISIBILITY
266 shared_lock(mutex_type& __m,
267 const chrono::time_point<_Clock, _Duration>& __abs_time)
269 __owns_(__m.try_lock_shared_until(__abs_time))
272 template <class _Rep, class _Period>
273 _LIBCPP_INLINE_VISIBILITY
274 shared_lock(mutex_type& __m,
275 const chrono::duration<_Rep, _Period>& __rel_time)
277 __owns_(__m.try_lock_shared_for(__rel_time))
280 _LIBCPP_INLINE_VISIBILITY
284 __m_->unlock_shared();
287 shared_lock(shared_lock const&) = delete;
288 shared_lock& operator=(shared_lock const&) = delete;
290 _LIBCPP_INLINE_VISIBILITY
291 shared_lock(shared_lock&& __u) noexcept
299 _LIBCPP_INLINE_VISIBILITY
300 shared_lock& operator=(shared_lock&& __u) noexcept
303 __m_->unlock_shared();
307 __owns_ = __u.__owns_;
315 template <class Rep, class Period>
316 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
317 template <class Clock, class Duration>
318 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
322 _LIBCPP_INLINE_VISIBILITY
323 void swap(shared_lock& __u) noexcept
325 _VSTD::swap(__m_, __u.__m_);
326 _VSTD::swap(__owns_, __u.__owns_);
329 _LIBCPP_INLINE_VISIBILITY
330 mutex_type* release() noexcept
332 mutex_type* __m = __m_;
339 _LIBCPP_INLINE_VISIBILITY
340 bool owns_lock() const noexcept {return __owns_;}
342 _LIBCPP_INLINE_VISIBILITY
343 explicit operator bool () const noexcept {return __owns_;}
345 _LIBCPP_INLINE_VISIBILITY
346 mutex_type* mutex() const noexcept {return __m_;}
349 template <class _Mutex>
351 shared_lock<_Mutex>::lock()
354 __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
356 __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
361 template <class _Mutex>
363 shared_lock<_Mutex>::try_lock()
366 __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
368 __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
369 __owns_ = __m_->try_lock_shared();
373 template <class _Mutex>
374 template <class _Rep, class _Period>
376 shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
379 __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
381 __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
382 __owns_ = __m_->try_lock_shared_for(__d);
386 template <class _Mutex>
387 template <class _Clock, class _Duration>
389 shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
392 __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
394 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
395 __owns_ = __m_->try_lock_shared_until(__t);
399 template <class _Mutex>
401 shared_lock<_Mutex>::unlock()
404 __throw_system_error(EPERM, "shared_lock::unlock: not locked");
405 __m_->unlock_shared();
409 template <class _Mutex>
410 inline _LIBCPP_INLINE_VISIBILITY
412 swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) noexcept
415 _LIBCPP_END_NAMESPACE_STD
417 #endif // _LIBCPP_STD_VER > 11
419 #endif // _LIBCPP_SHARED_MUTEX