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#include <__config> 126 127#if !defined(_LIBCPP_HAS_NO_THREADS) 128 129# include <__chrono/duration.h> 130# include <__chrono/steady_clock.h> 131# include <__chrono/time_point.h> 132# include <__condition_variable/condition_variable.h> 133# include <__memory/addressof.h> 134# include <__mutex/mutex.h> 135# include <__mutex/tag_types.h> 136# include <__mutex/unique_lock.h> 137# include <__system_error/system_error.h> 138# include <__utility/swap.h> 139# include <cerrno> 140# include <version> 141 142_LIBCPP_PUSH_MACROS 143# include <__undef_macros> 144 145# if _LIBCPP_STD_VER >= 14 146 147# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 148# pragma GCC system_header 149# endif 150 151_LIBCPP_BEGIN_NAMESPACE_STD 152 153struct _LIBCPP_EXPORTED_FROM_ABI __shared_mutex_base { 154 mutex __mut_; 155 condition_variable __gate1_; 156 condition_variable __gate2_; 157 unsigned __state_; 158 159 static const unsigned __write_entered_ = 1U << (sizeof(unsigned) * __CHAR_BIT__ - 1); 160 static const unsigned __n_readers_ = ~__write_entered_; 161 162 __shared_mutex_base(); 163 _LIBCPP_HIDE_FROM_ABI ~__shared_mutex_base() = default; 164 165 __shared_mutex_base(const __shared_mutex_base&) = delete; 166 __shared_mutex_base& operator=(const __shared_mutex_base&) = delete; 167 168 // Exclusive ownership 169 void lock(); // blocking 170 bool try_lock(); 171 void unlock(); 172 173 // Shared ownership 174 void lock_shared(); // blocking 175 bool try_lock_shared(); 176 void unlock_shared(); 177 178 // typedef implementation-defined native_handle_type; // See 30.2.3 179 // native_handle_type native_handle(); // See 30.2.3 180}; 181 182# if _LIBCPP_STD_VER >= 17 183class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_THREAD_SAFETY_ANNOTATION(__capability__("shared_mutex")) shared_mutex { 184 __shared_mutex_base __base_; 185 186public: 187 _LIBCPP_HIDE_FROM_ABI shared_mutex() : __base_() {} 188 _LIBCPP_HIDE_FROM_ABI ~shared_mutex() = default; 189 190 shared_mutex(const shared_mutex&) = delete; 191 shared_mutex& operator=(const shared_mutex&) = delete; 192 193 // Exclusive ownership 194 _LIBCPP_HIDE_FROM_ABI void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_capability__()) { 195 return __base_.lock(); 196 } 197 _LIBCPP_HIDE_FROM_ABI bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true)) { 198 return __base_.try_lock(); 199 } 200 _LIBCPP_HIDE_FROM_ABI void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_capability__()) { 201 return __base_.unlock(); 202 } 203 204 // Shared ownership 205 _LIBCPP_HIDE_FROM_ABI void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_shared_capability__()) { 206 return __base_.lock_shared(); 207 } 208 _LIBCPP_HIDE_FROM_ABI bool try_lock_shared() 209 _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true)) { 210 return __base_.try_lock_shared(); 211 } 212 _LIBCPP_HIDE_FROM_ABI void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_shared_capability__()) { 213 return __base_.unlock_shared(); 214 } 215 216 // typedef __shared_mutex_base::native_handle_type native_handle_type; 217 // _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return __base::unlock_shared(); } 218}; 219# endif 220 221class _LIBCPP_EXPORTED_FROM_ABI 222_LIBCPP_THREAD_SAFETY_ANNOTATION(__capability__("shared_timed_mutex")) shared_timed_mutex { 223 __shared_mutex_base __base_; 224 225public: 226 shared_timed_mutex(); 227 _LIBCPP_HIDE_FROM_ABI ~shared_timed_mutex() = default; 228 229 shared_timed_mutex(const shared_timed_mutex&) = delete; 230 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete; 231 232 // Exclusive ownership 233 void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_capability__()); 234 bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true)); 235 template <class _Rep, class _Period> 236 _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time) 237 _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true)) { 238 return try_lock_until(chrono::steady_clock::now() + __rel_time); 239 } 240 template <class _Clock, class _Duration> 241 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool 242 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time) 243 _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true)); 244 void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_capability__()); 245 246 // Shared ownership 247 void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_shared_capability__()); 248 bool try_lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true)); 249 template <class _Rep, class _Period> 250 _LIBCPP_HIDE_FROM_ABI bool try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time) 251 _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true)) { 252 return try_lock_shared_until(chrono::steady_clock::now() + __rel_time); 253 } 254 template <class _Clock, class _Duration> 255 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool 256 try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time) 257 _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true)); 258 void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_shared_capability__()); 259}; 260 261template <class _Clock, class _Duration> 262bool shared_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time) { 263 unique_lock<mutex> __lk(__base_.__mut_); 264 if (__base_.__state_ & __base_.__write_entered_) { 265 while (true) { 266 cv_status __status = __base_.__gate1_.wait_until(__lk, __abs_time); 267 if ((__base_.__state_ & __base_.__write_entered_) == 0) 268 break; 269 if (__status == cv_status::timeout) 270 return false; 271 } 272 } 273 __base_.__state_ |= __base_.__write_entered_; 274 if (__base_.__state_ & __base_.__n_readers_) { 275 while (true) { 276 cv_status __status = __base_.__gate2_.wait_until(__lk, __abs_time); 277 if ((__base_.__state_ & __base_.__n_readers_) == 0) 278 break; 279 if (__status == cv_status::timeout) { 280 __base_.__state_ &= ~__base_.__write_entered_; 281 __base_.__gate1_.notify_all(); 282 return false; 283 } 284 } 285 } 286 return true; 287} 288 289template <class _Clock, class _Duration> 290bool shared_timed_mutex::try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time) { 291 unique_lock<mutex> __lk(__base_.__mut_); 292 if ((__base_.__state_ & __base_.__write_entered_) || 293 (__base_.__state_ & __base_.__n_readers_) == __base_.__n_readers_) { 294 while (true) { 295 cv_status __status = __base_.__gate1_.wait_until(__lk, __abs_time); 296 if ((__base_.__state_ & __base_.__write_entered_) == 0 && 297 (__base_.__state_ & __base_.__n_readers_) < __base_.__n_readers_) 298 break; 299 if (__status == cv_status::timeout) 300 return false; 301 } 302 } 303 unsigned __num_readers = (__base_.__state_ & __base_.__n_readers_) + 1; 304 __base_.__state_ &= ~__base_.__n_readers_; 305 __base_.__state_ |= __num_readers; 306 return true; 307} 308 309template <class _Mutex> 310class shared_lock { 311public: 312 typedef _Mutex mutex_type; 313 314private: 315 mutex_type* __m_; 316 bool __owns_; 317 318public: 319 _LIBCPP_HIDE_FROM_ABI shared_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {} 320 321 _LIBCPP_HIDE_FROM_ABI explicit shared_lock(mutex_type& __m) : __m_(std::addressof(__m)), __owns_(true) { 322 __m_->lock_shared(); 323 } 324 325 _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT 326 : __m_(std::addressof(__m)), 327 __owns_(false) {} 328 329 _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, try_to_lock_t) 330 : __m_(std::addressof(__m)), __owns_(__m.try_lock_shared()) {} 331 332 _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, adopt_lock_t) : __m_(std::addressof(__m)), __owns_(true) {} 333 334 template <class _Clock, class _Duration> 335 _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __abs_time) 336 : __m_(std::addressof(__m)), __owns_(__m.try_lock_shared_until(__abs_time)) {} 337 338 template <class _Rep, class _Period> 339 _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __rel_time) 340 : __m_(std::addressof(__m)), __owns_(__m.try_lock_shared_for(__rel_time)) {} 341 342 _LIBCPP_HIDE_FROM_ABI ~shared_lock() { 343 if (__owns_) 344 __m_->unlock_shared(); 345 } 346 347 shared_lock(shared_lock const&) = delete; 348 shared_lock& operator=(shared_lock const&) = delete; 349 350 _LIBCPP_HIDE_FROM_ABI shared_lock(shared_lock&& __u) _NOEXCEPT : __m_(__u.__m_), __owns_(__u.__owns_) { 351 __u.__m_ = nullptr; 352 __u.__owns_ = false; 353 } 354 355 _LIBCPP_HIDE_FROM_ABI shared_lock& operator=(shared_lock&& __u) _NOEXCEPT { 356 if (__owns_) 357 __m_->unlock_shared(); 358 __m_ = nullptr; 359 __owns_ = false; 360 __m_ = __u.__m_; 361 __owns_ = __u.__owns_; 362 __u.__m_ = nullptr; 363 __u.__owns_ = false; 364 return *this; 365 } 366 367 _LIBCPP_HIDE_FROM_ABI void lock(); 368 _LIBCPP_HIDE_FROM_ABI bool try_lock(); 369 template <class _Rep, class _Period> 370 _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time); 371 template <class _Clock, class _Duration> 372 _LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time); 373 _LIBCPP_HIDE_FROM_ABI void unlock(); 374 375 // Setters 376 _LIBCPP_HIDE_FROM_ABI void swap(shared_lock& __u) _NOEXCEPT { 377 std::swap(__m_, __u.__m_); 378 std::swap(__owns_, __u.__owns_); 379 } 380 381 _LIBCPP_HIDE_FROM_ABI mutex_type* release() _NOEXCEPT { 382 mutex_type* __m = __m_; 383 __m_ = nullptr; 384 __owns_ = false; 385 return __m; 386 } 387 388 // Getters 389 _LIBCPP_HIDE_FROM_ABI bool owns_lock() const _NOEXCEPT { return __owns_; } 390 391 _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __owns_; } 392 393 _LIBCPP_HIDE_FROM_ABI mutex_type* mutex() const _NOEXCEPT { return __m_; } 394}; 395_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(shared_lock); 396 397template <class _Mutex> 398void shared_lock<_Mutex>::lock() { 399 if (__m_ == nullptr) 400 __throw_system_error(EPERM, "shared_lock::lock: references null mutex"); 401 if (__owns_) 402 __throw_system_error(EDEADLK, "shared_lock::lock: already locked"); 403 __m_->lock_shared(); 404 __owns_ = true; 405} 406 407template <class _Mutex> 408bool shared_lock<_Mutex>::try_lock() { 409 if (__m_ == nullptr) 410 __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex"); 411 if (__owns_) 412 __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked"); 413 __owns_ = __m_->try_lock_shared(); 414 return __owns_; 415} 416 417template <class _Mutex> 418template <class _Rep, class _Period> 419bool shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d) { 420 if (__m_ == nullptr) 421 __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex"); 422 if (__owns_) 423 __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked"); 424 __owns_ = __m_->try_lock_shared_for(__d); 425 return __owns_; 426} 427 428template <class _Mutex> 429template <class _Clock, class _Duration> 430bool shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) { 431 if (__m_ == nullptr) 432 __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex"); 433 if (__owns_) 434 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked"); 435 __owns_ = __m_->try_lock_shared_until(__t); 436 return __owns_; 437} 438 439template <class _Mutex> 440void shared_lock<_Mutex>::unlock() { 441 if (!__owns_) 442 __throw_system_error(EPERM, "shared_lock::unlock: not locked"); 443 __m_->unlock_shared(); 444 __owns_ = false; 445} 446 447template <class _Mutex> 448inline _LIBCPP_HIDE_FROM_ABI void swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT { 449 __x.swap(__y); 450} 451 452_LIBCPP_END_NAMESPACE_STD 453 454# endif // _LIBCPP_STD_VER >= 14 455 456_LIBCPP_POP_MACROS 457 458#endif // !defined(_LIBCPP_HAS_NO_THREADS) 459 460#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20 461# include <system_error> 462#endif 463 464#endif // _LIBCPP_SHARED_MUTEX 465