1// -*- C++ -*- 2//===------------------------ shared_mutex --------------------------------===// 3// 4// The LLVM Compiler Infrastructure 5// 6// This file is dual licensed under the MIT and the University of Illinois Open 7// Source Licenses. See LICENSE.TXT for details. 8// 9//===----------------------------------------------------------------------===// 10 11#ifndef _LIBCPP_SHARED_MUTEX 12#define _LIBCPP_SHARED_MUTEX 13 14/* 15 shared_mutex synopsis 16 17// C++1y 18 19namespace std 20{ 21 22class shared_mutex // C++17 23{ 24public: 25 shared_mutex(); 26 ~shared_mutex(); 27 28 shared_mutex(const shared_mutex&) = delete; 29 shared_mutex& operator=(const shared_mutex&) = delete; 30 31 // Exclusive ownership 32 void lock(); // blocking 33 bool try_lock(); 34 void unlock(); 35 36 // Shared ownership 37 void lock_shared(); // blocking 38 bool try_lock_shared(); 39 void unlock_shared(); 40 41 typedef implementation-defined native_handle_type; // See 30.2.3 42 native_handle_type native_handle(); // See 30.2.3 43}; 44 45class shared_timed_mutex 46{ 47public: 48 shared_timed_mutex(); 49 ~shared_timed_mutex(); 50 51 shared_timed_mutex(const shared_timed_mutex&) = delete; 52 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete; 53 54 // Exclusive ownership 55 void lock(); // blocking 56 bool try_lock(); 57 template <class Rep, class Period> 58 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); 59 template <class Clock, class Duration> 60 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); 61 void unlock(); 62 63 // Shared ownership 64 void lock_shared(); // blocking 65 bool try_lock_shared(); 66 template <class Rep, class Period> 67 bool 68 try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time); 69 template <class Clock, class Duration> 70 bool 71 try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time); 72 void unlock_shared(); 73}; 74 75template <class Mutex> 76class shared_lock 77{ 78public: 79 typedef Mutex mutex_type; 80 81 // Shared locking 82 shared_lock() noexcept; 83 explicit shared_lock(mutex_type& m); // blocking 84 shared_lock(mutex_type& m, defer_lock_t) noexcept; 85 shared_lock(mutex_type& m, try_to_lock_t); 86 shared_lock(mutex_type& m, adopt_lock_t); 87 template <class Clock, class Duration> 88 shared_lock(mutex_type& m, 89 const chrono::time_point<Clock, Duration>& abs_time); 90 template <class Rep, class Period> 91 shared_lock(mutex_type& m, 92 const chrono::duration<Rep, Period>& rel_time); 93 ~shared_lock(); 94 95 shared_lock(shared_lock const&) = delete; 96 shared_lock& operator=(shared_lock const&) = delete; 97 98 shared_lock(shared_lock&& u) noexcept; 99 shared_lock& operator=(shared_lock&& u) noexcept; 100 101 void lock(); // blocking 102 bool try_lock(); 103 template <class Rep, class Period> 104 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); 105 template <class Clock, class Duration> 106 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); 107 void unlock(); 108 109 // Setters 110 void swap(shared_lock& u) noexcept; 111 mutex_type* release() noexcept; 112 113 // Getters 114 bool owns_lock() const noexcept; 115 explicit operator bool () const noexcept; 116 mutex_type* mutex() const noexcept; 117}; 118 119template <class Mutex> 120 void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept; 121 122} // std 123 124*/ 125 126#include <__config> 127 128#if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_SHARED_MUTEX) 129 130#include <__mutex_base> 131 132#include <__undef_min_max> 133 134#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 135#pragma GCC system_header 136#endif 137 138#ifdef _LIBCPP_HAS_NO_THREADS 139#error <shared_mutex> is not supported on this single threaded system 140#else // !_LIBCPP_HAS_NO_THREADS 141 142_LIBCPP_BEGIN_NAMESPACE_STD 143 144struct _LIBCPP_TYPE_VIS __shared_mutex_base 145{ 146 mutex __mut_; 147 condition_variable __gate1_; 148 condition_variable __gate2_; 149 unsigned __state_; 150 151 static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1); 152 static const unsigned __n_readers_ = ~__write_entered_; 153 154 __shared_mutex_base(); 155 _LIBCPP_INLINE_VISIBILITY ~__shared_mutex_base() = default; 156 157 __shared_mutex_base(const __shared_mutex_base&) = delete; 158 __shared_mutex_base& operator=(const __shared_mutex_base&) = delete; 159 160 // Exclusive ownership 161 void lock(); // blocking 162 bool try_lock(); 163 void unlock(); 164 165 // Shared ownership 166 void lock_shared(); // blocking 167 bool try_lock_shared(); 168 void unlock_shared(); 169 170// typedef implementation-defined native_handle_type; // See 30.2.3 171// native_handle_type native_handle(); // See 30.2.3 172}; 173 174 175#if _LIBCPP_STD_VER > 14 176class _LIBCPP_TYPE_VIS shared_mutex 177{ 178 __shared_mutex_base __base; 179public: 180 shared_mutex() : __base() {} 181 _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default; 182 183 shared_mutex(const shared_mutex&) = delete; 184 shared_mutex& operator=(const shared_mutex&) = delete; 185 186 // Exclusive ownership 187 _LIBCPP_INLINE_VISIBILITY void lock() { return __base.lock(); } 188 _LIBCPP_INLINE_VISIBILITY bool try_lock() { return __base.try_lock(); } 189 _LIBCPP_INLINE_VISIBILITY void unlock() { return __base.unlock(); } 190 191 // Shared ownership 192 _LIBCPP_INLINE_VISIBILITY void lock_shared() { return __base.lock_shared(); } 193 _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() { return __base.try_lock_shared(); } 194 _LIBCPP_INLINE_VISIBILITY void unlock_shared() { return __base.unlock_shared(); } 195 196// typedef __shared_mutex_base::native_handle_type native_handle_type; 197// _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() { return __base::unlock_shared(); } 198}; 199#endif 200 201 202class _LIBCPP_TYPE_VIS shared_timed_mutex 203{ 204 __shared_mutex_base __base; 205public: 206 shared_timed_mutex(); 207 _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default; 208 209 shared_timed_mutex(const shared_timed_mutex&) = delete; 210 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete; 211 212 // Exclusive ownership 213 void lock(); 214 bool try_lock(); 215 template <class _Rep, class _Period> 216 _LIBCPP_INLINE_VISIBILITY 217 bool 218 try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time) 219 { 220 return try_lock_until(chrono::steady_clock::now() + __rel_time); 221 } 222 template <class _Clock, class _Duration> 223 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS 224 bool 225 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time); 226 void unlock(); 227 228 // Shared ownership 229 void lock_shared(); 230 bool try_lock_shared(); 231 template <class _Rep, class _Period> 232 _LIBCPP_INLINE_VISIBILITY 233 bool 234 try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time) 235 { 236 return try_lock_shared_until(chrono::steady_clock::now() + __rel_time); 237 } 238 template <class _Clock, class _Duration> 239 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS 240 bool 241 try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time); 242 void unlock_shared(); 243}; 244 245template <class _Clock, class _Duration> 246bool 247shared_timed_mutex::try_lock_until( 248 const chrono::time_point<_Clock, _Duration>& __abs_time) 249{ 250 unique_lock<mutex> __lk(__base.__mut_); 251 if (__base.__state_ & __base.__write_entered_) 252 { 253 while (true) 254 { 255 cv_status __status = __base.__gate1_.wait_until(__lk, __abs_time); 256 if ((__base.__state_ & __base.__write_entered_) == 0) 257 break; 258 if (__status == cv_status::timeout) 259 return false; 260 } 261 } 262 __base.__state_ |= __base.__write_entered_; 263 if (__base.__state_ & __base.__n_readers_) 264 { 265 while (true) 266 { 267 cv_status __status = __base.__gate2_.wait_until(__lk, __abs_time); 268 if ((__base.__state_ & __base.__n_readers_) == 0) 269 break; 270 if (__status == cv_status::timeout) 271 { 272 __base.__state_ &= ~__base.__write_entered_; 273 __base.__gate1_.notify_all(); 274 return false; 275 } 276 } 277 } 278 return true; 279} 280 281template <class _Clock, class _Duration> 282bool 283shared_timed_mutex::try_lock_shared_until( 284 const chrono::time_point<_Clock, _Duration>& __abs_time) 285{ 286 unique_lock<mutex> __lk(__base.__mut_); 287 if ((__base.__state_ & __base.__write_entered_) || (__base.__state_ & __base.__n_readers_) == __base.__n_readers_) 288 { 289 while (true) 290 { 291 cv_status status = __base.__gate1_.wait_until(__lk, __abs_time); 292 if ((__base.__state_ & __base.__write_entered_) == 0 && 293 (__base.__state_ & __base.__n_readers_) < __base.__n_readers_) 294 break; 295 if (status == cv_status::timeout) 296 return false; 297 } 298 } 299 unsigned __num_readers = (__base.__state_ & __base.__n_readers_) + 1; 300 __base.__state_ &= ~__base.__n_readers_; 301 __base.__state_ |= __num_readers; 302 return true; 303} 304 305template <class _Mutex> 306class shared_lock 307{ 308public: 309 typedef _Mutex mutex_type; 310 311private: 312 mutex_type* __m_; 313 bool __owns_; 314 315public: 316 _LIBCPP_INLINE_VISIBILITY 317 shared_lock() _NOEXCEPT 318 : __m_(nullptr), 319 __owns_(false) 320 {} 321 322 _LIBCPP_INLINE_VISIBILITY 323 explicit shared_lock(mutex_type& __m) 324 : __m_(_VSTD::addressof(__m)), 325 __owns_(true) 326 {__m_->lock_shared();} 327 328 _LIBCPP_INLINE_VISIBILITY 329 shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT 330 : __m_(_VSTD::addressof(__m)), 331 __owns_(false) 332 {} 333 334 _LIBCPP_INLINE_VISIBILITY 335 shared_lock(mutex_type& __m, try_to_lock_t) 336 : __m_(_VSTD::addressof(__m)), 337 __owns_(__m.try_lock_shared()) 338 {} 339 340 _LIBCPP_INLINE_VISIBILITY 341 shared_lock(mutex_type& __m, adopt_lock_t) 342 : __m_(_VSTD::addressof(__m)), 343 __owns_(true) 344 {} 345 346 template <class _Clock, class _Duration> 347 _LIBCPP_INLINE_VISIBILITY 348 shared_lock(mutex_type& __m, 349 const chrono::time_point<_Clock, _Duration>& __abs_time) 350 : __m_(_VSTD::addressof(__m)), 351 __owns_(__m.try_lock_shared_until(__abs_time)) 352 {} 353 354 template <class _Rep, class _Period> 355 _LIBCPP_INLINE_VISIBILITY 356 shared_lock(mutex_type& __m, 357 const chrono::duration<_Rep, _Period>& __rel_time) 358 : __m_(_VSTD::addressof(__m)), 359 __owns_(__m.try_lock_shared_for(__rel_time)) 360 {} 361 362 _LIBCPP_INLINE_VISIBILITY 363 ~shared_lock() 364 { 365 if (__owns_) 366 __m_->unlock_shared(); 367 } 368 369 shared_lock(shared_lock const&) = delete; 370 shared_lock& operator=(shared_lock const&) = delete; 371 372 _LIBCPP_INLINE_VISIBILITY 373 shared_lock(shared_lock&& __u) _NOEXCEPT 374 : __m_(__u.__m_), 375 __owns_(__u.__owns_) 376 { 377 __u.__m_ = nullptr; 378 __u.__owns_ = false; 379 } 380 381 _LIBCPP_INLINE_VISIBILITY 382 shared_lock& operator=(shared_lock&& __u) _NOEXCEPT 383 { 384 if (__owns_) 385 __m_->unlock_shared(); 386 __m_ = nullptr; 387 __owns_ = false; 388 __m_ = __u.__m_; 389 __owns_ = __u.__owns_; 390 __u.__m_ = nullptr; 391 __u.__owns_ = false; 392 return *this; 393 } 394 395 void lock(); 396 bool try_lock(); 397 template <class Rep, class Period> 398 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); 399 template <class Clock, class Duration> 400 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); 401 void unlock(); 402 403 // Setters 404 _LIBCPP_INLINE_VISIBILITY 405 void swap(shared_lock& __u) _NOEXCEPT 406 { 407 _VSTD::swap(__m_, __u.__m_); 408 _VSTD::swap(__owns_, __u.__owns_); 409 } 410 411 _LIBCPP_INLINE_VISIBILITY 412 mutex_type* release() _NOEXCEPT 413 { 414 mutex_type* __m = __m_; 415 __m_ = nullptr; 416 __owns_ = false; 417 return __m; 418 } 419 420 // Getters 421 _LIBCPP_INLINE_VISIBILITY 422 bool owns_lock() const _NOEXCEPT {return __owns_;} 423 424 _LIBCPP_INLINE_VISIBILITY 425 explicit operator bool () const _NOEXCEPT {return __owns_;} 426 427 _LIBCPP_INLINE_VISIBILITY 428 mutex_type* mutex() const _NOEXCEPT {return __m_;} 429}; 430 431template <class _Mutex> 432void 433shared_lock<_Mutex>::lock() 434{ 435 if (__m_ == nullptr) 436 __throw_system_error(EPERM, "shared_lock::lock: references null mutex"); 437 if (__owns_) 438 __throw_system_error(EDEADLK, "shared_lock::lock: already locked"); 439 __m_->lock_shared(); 440 __owns_ = true; 441} 442 443template <class _Mutex> 444bool 445shared_lock<_Mutex>::try_lock() 446{ 447 if (__m_ == nullptr) 448 __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex"); 449 if (__owns_) 450 __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked"); 451 __owns_ = __m_->try_lock_shared(); 452 return __owns_; 453} 454 455template <class _Mutex> 456template <class _Rep, class _Period> 457bool 458shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d) 459{ 460 if (__m_ == nullptr) 461 __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex"); 462 if (__owns_) 463 __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked"); 464 __owns_ = __m_->try_lock_shared_for(__d); 465 return __owns_; 466} 467 468template <class _Mutex> 469template <class _Clock, class _Duration> 470bool 471shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) 472{ 473 if (__m_ == nullptr) 474 __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex"); 475 if (__owns_) 476 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked"); 477 __owns_ = __m_->try_lock_shared_until(__t); 478 return __owns_; 479} 480 481template <class _Mutex> 482void 483shared_lock<_Mutex>::unlock() 484{ 485 if (!__owns_) 486 __throw_system_error(EPERM, "shared_lock::unlock: not locked"); 487 __m_->unlock_shared(); 488 __owns_ = false; 489} 490 491template <class _Mutex> 492inline _LIBCPP_INLINE_VISIBILITY 493void 494swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT 495 {__x.swap(__y);} 496 497_LIBCPP_END_NAMESPACE_STD 498 499#endif // !_LIBCPP_HAS_NO_THREADS 500 501#endif // _LIBCPP_STD_VER > 11 502 503#endif // _LIBCPP_SHARED_MUTEX 504