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