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 #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 144 struct _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 176 class _LIBCPP_TYPE_VIS shared_mutex 177 { 178 __shared_mutex_base __base; 179 public: 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 202 class _LIBCPP_TYPE_VIS shared_timed_mutex 203 { 204 __shared_mutex_base __base; 205 public: 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 245 template <class _Clock, class _Duration> 246 bool 247 shared_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 281 template <class _Clock, class _Duration> 282 bool 283 shared_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 305 template <class _Mutex> 306 class shared_lock 307 { 308 public: 309 typedef _Mutex mutex_type; 310 311 private: 312 mutex_type* __m_; 313 bool __owns_; 314 315 public: 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 431 template <class _Mutex> 432 void 433 shared_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 443 template <class _Mutex> 444 bool 445 shared_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 455 template <class _Mutex> 456 template <class _Rep, class _Period> 457 bool 458 shared_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 468 template <class _Mutex> 469 template <class _Clock, class _Duration> 470 bool 471 shared_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 481 template <class _Mutex> 482 void 483 shared_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 491 template <class _Mutex> 492 inline _LIBCPP_INLINE_VISIBILITY 493 void 494 swap(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