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