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