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 bool 224 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time); 225 void unlock(); 226 227 // Shared ownership 228 void lock_shared(); 229 bool try_lock_shared(); 230 template <class _Rep, class _Period> 231 _LIBCPP_INLINE_VISIBILITY 232 bool 233 try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time) 234 { 235 return try_lock_shared_until(chrono::steady_clock::now() + __rel_time); 236 } 237 template <class _Clock, class _Duration> 238 bool 239 try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time); 240 void unlock_shared(); 241 }; 242 243 template <class _Clock, class _Duration> 244 bool 245 shared_timed_mutex::try_lock_until( 246 const chrono::time_point<_Clock, _Duration>& __abs_time) 247 { 248 unique_lock<mutex> __lk(__base.__mut_); 249 if (__base.__state_ & __base.__write_entered_) 250 { 251 while (true) 252 { 253 cv_status __status = __base.__gate1_.wait_until(__lk, __abs_time); 254 if ((__base.__state_ & __base.__write_entered_) == 0) 255 break; 256 if (__status == cv_status::timeout) 257 return false; 258 } 259 } 260 __base.__state_ |= __base.__write_entered_; 261 if (__base.__state_ & __base.__n_readers_) 262 { 263 while (true) 264 { 265 cv_status __status = __base.__gate2_.wait_until(__lk, __abs_time); 266 if ((__base.__state_ & __base.__n_readers_) == 0) 267 break; 268 if (__status == cv_status::timeout) 269 { 270 __base.__state_ &= ~__base.__write_entered_; 271 __base.__gate1_.notify_all(); 272 return false; 273 } 274 } 275 } 276 return true; 277 } 278 279 template <class _Clock, class _Duration> 280 bool 281 shared_timed_mutex::try_lock_shared_until( 282 const chrono::time_point<_Clock, _Duration>& __abs_time) 283 { 284 unique_lock<mutex> __lk(__base.__mut_); 285 if ((__base.__state_ & __base.__write_entered_) || (__base.__state_ & __base.__n_readers_) == __base.__n_readers_) 286 { 287 while (true) 288 { 289 cv_status status = __base.__gate1_.wait_until(__lk, __abs_time); 290 if ((__base.__state_ & __base.__write_entered_) == 0 && 291 (__base.__state_ & __base.__n_readers_) < __base.__n_readers_) 292 break; 293 if (status == cv_status::timeout) 294 return false; 295 } 296 } 297 unsigned __num_readers = (__base.__state_ & __base.__n_readers_) + 1; 298 __base.__state_ &= ~__base.__n_readers_; 299 __base.__state_ |= __num_readers; 300 return true; 301 } 302 303 template <class _Mutex> 304 class shared_lock 305 { 306 public: 307 typedef _Mutex mutex_type; 308 309 private: 310 mutex_type* __m_; 311 bool __owns_; 312 313 public: 314 _LIBCPP_INLINE_VISIBILITY 315 shared_lock() _NOEXCEPT 316 : __m_(nullptr), 317 __owns_(false) 318 {} 319 320 _LIBCPP_INLINE_VISIBILITY 321 explicit shared_lock(mutex_type& __m) 322 : __m_(&__m), 323 __owns_(true) 324 {__m_->lock_shared();} 325 326 _LIBCPP_INLINE_VISIBILITY 327 shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT 328 : __m_(&__m), 329 __owns_(false) 330 {} 331 332 _LIBCPP_INLINE_VISIBILITY 333 shared_lock(mutex_type& __m, try_to_lock_t) 334 : __m_(&__m), 335 __owns_(__m.try_lock_shared()) 336 {} 337 338 _LIBCPP_INLINE_VISIBILITY 339 shared_lock(mutex_type& __m, adopt_lock_t) 340 : __m_(&__m), 341 __owns_(true) 342 {} 343 344 template <class _Clock, class _Duration> 345 _LIBCPP_INLINE_VISIBILITY 346 shared_lock(mutex_type& __m, 347 const chrono::time_point<_Clock, _Duration>& __abs_time) 348 : __m_(&__m), 349 __owns_(__m.try_lock_shared_until(__abs_time)) 350 {} 351 352 template <class _Rep, class _Period> 353 _LIBCPP_INLINE_VISIBILITY 354 shared_lock(mutex_type& __m, 355 const chrono::duration<_Rep, _Period>& __rel_time) 356 : __m_(&__m), 357 __owns_(__m.try_lock_shared_for(__rel_time)) 358 {} 359 360 _LIBCPP_INLINE_VISIBILITY 361 ~shared_lock() 362 { 363 if (__owns_) 364 __m_->unlock_shared(); 365 } 366 367 shared_lock(shared_lock const&) = delete; 368 shared_lock& operator=(shared_lock const&) = delete; 369 370 _LIBCPP_INLINE_VISIBILITY 371 shared_lock(shared_lock&& __u) _NOEXCEPT 372 : __m_(__u.__m_), 373 __owns_(__u.__owns_) 374 { 375 __u.__m_ = nullptr; 376 __u.__owns_ = false; 377 } 378 379 _LIBCPP_INLINE_VISIBILITY 380 shared_lock& operator=(shared_lock&& __u) _NOEXCEPT 381 { 382 if (__owns_) 383 __m_->unlock_shared(); 384 __m_ = nullptr; 385 __owns_ = false; 386 __m_ = __u.__m_; 387 __owns_ = __u.__owns_; 388 __u.__m_ = nullptr; 389 __u.__owns_ = false; 390 return *this; 391 } 392 393 void lock(); 394 bool try_lock(); 395 template <class Rep, class Period> 396 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); 397 template <class Clock, class Duration> 398 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); 399 void unlock(); 400 401 // Setters 402 _LIBCPP_INLINE_VISIBILITY 403 void swap(shared_lock& __u) _NOEXCEPT 404 { 405 _VSTD::swap(__m_, __u.__m_); 406 _VSTD::swap(__owns_, __u.__owns_); 407 } 408 409 _LIBCPP_INLINE_VISIBILITY 410 mutex_type* release() _NOEXCEPT 411 { 412 mutex_type* __m = __m_; 413 __m_ = nullptr; 414 __owns_ = false; 415 return __m; 416 } 417 418 // Getters 419 _LIBCPP_INLINE_VISIBILITY 420 bool owns_lock() const _NOEXCEPT {return __owns_;} 421 422 _LIBCPP_INLINE_VISIBILITY 423 explicit operator bool () const _NOEXCEPT {return __owns_;} 424 425 _LIBCPP_INLINE_VISIBILITY 426 mutex_type* mutex() const _NOEXCEPT {return __m_;} 427 }; 428 429 template <class _Mutex> 430 void 431 shared_lock<_Mutex>::lock() 432 { 433 if (__m_ == nullptr) 434 __throw_system_error(EPERM, "shared_lock::lock: references null mutex"); 435 if (__owns_) 436 __throw_system_error(EDEADLK, "shared_lock::lock: already locked"); 437 __m_->lock_shared(); 438 __owns_ = true; 439 } 440 441 template <class _Mutex> 442 bool 443 shared_lock<_Mutex>::try_lock() 444 { 445 if (__m_ == nullptr) 446 __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex"); 447 if (__owns_) 448 __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked"); 449 __owns_ = __m_->try_lock_shared(); 450 return __owns_; 451 } 452 453 template <class _Mutex> 454 template <class _Rep, class _Period> 455 bool 456 shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d) 457 { 458 if (__m_ == nullptr) 459 __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex"); 460 if (__owns_) 461 __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked"); 462 __owns_ = __m_->try_lock_shared_for(__d); 463 return __owns_; 464 } 465 466 template <class _Mutex> 467 template <class _Clock, class _Duration> 468 bool 469 shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) 470 { 471 if (__m_ == nullptr) 472 __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex"); 473 if (__owns_) 474 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked"); 475 __owns_ = __m_->try_lock_shared_until(__t); 476 return __owns_; 477 } 478 479 template <class _Mutex> 480 void 481 shared_lock<_Mutex>::unlock() 482 { 483 if (!__owns_) 484 __throw_system_error(EPERM, "shared_lock::unlock: not locked"); 485 __m_->unlock_shared(); 486 __owns_ = false; 487 } 488 489 template <class _Mutex> 490 inline _LIBCPP_INLINE_VISIBILITY 491 void 492 swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT 493 {__x.swap(__y);} 494 495 _LIBCPP_END_NAMESPACE_STD 496 497 #endif // !_LIBCPP_HAS_NO_THREADS 498 499 #endif // _LIBCPP_STD_VER > 11 500 501 #endif // _LIBCPP_SHARED_MUTEX 502