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