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