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 434template <class _Mutex> 435void 436shared_lock<_Mutex>::lock() 437{ 438 if (__m_ == nullptr) 439 __throw_system_error(EPERM, "shared_lock::lock: references null mutex"); 440 if (__owns_) 441 __throw_system_error(EDEADLK, "shared_lock::lock: already locked"); 442 __m_->lock_shared(); 443 __owns_ = true; 444} 445 446template <class _Mutex> 447bool 448shared_lock<_Mutex>::try_lock() 449{ 450 if (__m_ == nullptr) 451 __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex"); 452 if (__owns_) 453 __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked"); 454 __owns_ = __m_->try_lock_shared(); 455 return __owns_; 456} 457 458template <class _Mutex> 459template <class _Rep, class _Period> 460bool 461shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d) 462{ 463 if (__m_ == nullptr) 464 __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex"); 465 if (__owns_) 466 __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked"); 467 __owns_ = __m_->try_lock_shared_for(__d); 468 return __owns_; 469} 470 471template <class _Mutex> 472template <class _Clock, class _Duration> 473bool 474shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) 475{ 476 if (__m_ == nullptr) 477 __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex"); 478 if (__owns_) 479 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked"); 480 __owns_ = __m_->try_lock_shared_until(__t); 481 return __owns_; 482} 483 484template <class _Mutex> 485void 486shared_lock<_Mutex>::unlock() 487{ 488 if (!__owns_) 489 __throw_system_error(EPERM, "shared_lock::unlock: not locked"); 490 __m_->unlock_shared(); 491 __owns_ = false; 492} 493 494template <class _Mutex> 495inline _LIBCPP_INLINE_VISIBILITY 496void 497swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT 498 {__x.swap(__y);} 499 500_LIBCPP_END_NAMESPACE_STD 501 502#endif // !_LIBCPP_HAS_NO_THREADS 503 504#endif // _LIBCPP_STD_VER > 11 505 506_LIBCPP_POP_MACROS 507 508#endif // _LIBCPP_SHARED_MUTEX 509