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 19 namespace std 20 { 21 22 class shared_mutex // C++17 23 { 24 public: 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 45 class shared_timed_mutex 46 { 47 public: 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 75 template <class Mutex> 76 class shared_lock 77 { 78 public: 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 119 template <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 146 struct _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 178 class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_mutex 179 { 180 __shared_mutex_base __base; 181 public: 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 204 class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_timed_mutex 205 { 206 __shared_mutex_base __base; 207 public: 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 247 template <class _Clock, class _Duration> 248 bool 249 shared_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 283 template <class _Clock, class _Duration> 284 bool 285 shared_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 307 template <class _Mutex> 308 class shared_lock 309 { 310 public: 311 typedef _Mutex mutex_type; 312 313 private: 314 mutex_type* __m_; 315 bool __owns_; 316 317 public: 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 433 template <class _Mutex> 434 void 435 shared_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 445 template <class _Mutex> 446 bool 447 shared_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 457 template <class _Mutex> 458 template <class _Rep, class _Period> 459 bool 460 shared_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 470 template <class _Mutex> 471 template <class _Clock, class _Duration> 472 bool 473 shared_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 483 template <class _Mutex> 484 void 485 shared_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 493 template <class _Mutex> 494 inline _LIBCPP_INLINE_VISIBILITY 495 void 496 swap(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