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_timed_mutex 23 { 24 public: 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 52 template <class Mutex> 53 class shared_lock 54 { 55 public: 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 96 template <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 121 class _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_; 130 public: 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 168 template <class _Clock, class _Duration> 169 bool 170 shared_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 return false; 197 } 198 } 199 } 200 return true; 201 } 202 203 template <class _Clock, class _Duration> 204 bool 205 shared_timed_mutex::try_lock_shared_until( 206 const chrono::time_point<_Clock, _Duration>& __abs_time) 207 { 208 unique_lock<mutex> __lk(__mut_); 209 if ((__state_ & __write_entered_) || (__state_ & __n_readers_) == __n_readers_) 210 { 211 while (true) 212 { 213 cv_status status = __gate1_.wait_until(__lk, __abs_time); 214 if ((__state_ & __write_entered_) == 0 && 215 (__state_ & __n_readers_) < __n_readers_) 216 break; 217 if (status == cv_status::timeout) 218 return false; 219 } 220 } 221 unsigned __num_readers = (__state_ & __n_readers_) + 1; 222 __state_ &= ~__n_readers_; 223 __state_ |= __num_readers; 224 return true; 225 } 226 227 template <class _Mutex> 228 class shared_lock 229 { 230 public: 231 typedef _Mutex mutex_type; 232 233 private: 234 mutex_type* __m_; 235 bool __owns_; 236 237 public: 238 _LIBCPP_INLINE_VISIBILITY 239 shared_lock() _NOEXCEPT 240 : __m_(nullptr), 241 __owns_(false) 242 {} 243 244 _LIBCPP_INLINE_VISIBILITY 245 explicit shared_lock(mutex_type& __m) 246 : __m_(&__m), 247 __owns_(true) 248 {__m_->lock_shared();} 249 250 _LIBCPP_INLINE_VISIBILITY 251 shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT 252 : __m_(&__m), 253 __owns_(false) 254 {} 255 256 _LIBCPP_INLINE_VISIBILITY 257 shared_lock(mutex_type& __m, try_to_lock_t) 258 : __m_(&__m), 259 __owns_(__m.try_lock_shared()) 260 {} 261 262 _LIBCPP_INLINE_VISIBILITY 263 shared_lock(mutex_type& __m, adopt_lock_t) 264 : __m_(&__m), 265 __owns_(true) 266 {} 267 268 template <class _Clock, class _Duration> 269 _LIBCPP_INLINE_VISIBILITY 270 shared_lock(mutex_type& __m, 271 const chrono::time_point<_Clock, _Duration>& __abs_time) 272 : __m_(&__m), 273 __owns_(__m.try_lock_shared_until(__abs_time)) 274 {} 275 276 template <class _Rep, class _Period> 277 _LIBCPP_INLINE_VISIBILITY 278 shared_lock(mutex_type& __m, 279 const chrono::duration<_Rep, _Period>& __rel_time) 280 : __m_(&__m), 281 __owns_(__m.try_lock_shared_for(__rel_time)) 282 {} 283 284 _LIBCPP_INLINE_VISIBILITY 285 ~shared_lock() 286 { 287 if (__owns_) 288 __m_->unlock_shared(); 289 } 290 291 shared_lock(shared_lock const&) = delete; 292 shared_lock& operator=(shared_lock const&) = delete; 293 294 _LIBCPP_INLINE_VISIBILITY 295 shared_lock(shared_lock&& __u) _NOEXCEPT 296 : __m_(__u.__m_), 297 __owns_(__u.__owns_) 298 { 299 __u.__m_ = nullptr; 300 __u.__owns_ = false; 301 } 302 303 _LIBCPP_INLINE_VISIBILITY 304 shared_lock& operator=(shared_lock&& __u) _NOEXCEPT 305 { 306 if (__owns_) 307 __m_->unlock_shared(); 308 __m_ = nullptr; 309 __owns_ = false; 310 __m_ = __u.__m_; 311 __owns_ = __u.__owns_; 312 __u.__m_ = nullptr; 313 __u.__owns_ = false; 314 return *this; 315 } 316 317 void lock(); 318 bool try_lock(); 319 template <class Rep, class Period> 320 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); 321 template <class Clock, class Duration> 322 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); 323 void unlock(); 324 325 // Setters 326 _LIBCPP_INLINE_VISIBILITY 327 void swap(shared_lock& __u) _NOEXCEPT 328 { 329 _VSTD::swap(__m_, __u.__m_); 330 _VSTD::swap(__owns_, __u.__owns_); 331 } 332 333 _LIBCPP_INLINE_VISIBILITY 334 mutex_type* release() _NOEXCEPT 335 { 336 mutex_type* __m = __m_; 337 __m_ = nullptr; 338 __owns_ = false; 339 return __m; 340 } 341 342 // Getters 343 _LIBCPP_INLINE_VISIBILITY 344 bool owns_lock() const _NOEXCEPT {return __owns_;} 345 346 _LIBCPP_INLINE_VISIBILITY 347 explicit operator bool () const _NOEXCEPT {return __owns_;} 348 349 _LIBCPP_INLINE_VISIBILITY 350 mutex_type* mutex() const _NOEXCEPT {return __m_;} 351 }; 352 353 template <class _Mutex> 354 void 355 shared_lock<_Mutex>::lock() 356 { 357 if (__m_ == nullptr) 358 __throw_system_error(EPERM, "shared_lock::lock: references null mutex"); 359 if (__owns_) 360 __throw_system_error(EDEADLK, "shared_lock::lock: already locked"); 361 __m_->lock_shared(); 362 __owns_ = true; 363 } 364 365 template <class _Mutex> 366 bool 367 shared_lock<_Mutex>::try_lock() 368 { 369 if (__m_ == nullptr) 370 __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex"); 371 if (__owns_) 372 __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked"); 373 __owns_ = __m_->try_lock_shared(); 374 return __owns_; 375 } 376 377 template <class _Mutex> 378 template <class _Rep, class _Period> 379 bool 380 shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d) 381 { 382 if (__m_ == nullptr) 383 __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex"); 384 if (__owns_) 385 __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked"); 386 __owns_ = __m_->try_lock_shared_for(__d); 387 return __owns_; 388 } 389 390 template <class _Mutex> 391 template <class _Clock, class _Duration> 392 bool 393 shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) 394 { 395 if (__m_ == nullptr) 396 __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex"); 397 if (__owns_) 398 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked"); 399 __owns_ = __m_->try_lock_shared_until(__t); 400 return __owns_; 401 } 402 403 template <class _Mutex> 404 void 405 shared_lock<_Mutex>::unlock() 406 { 407 if (!__owns_) 408 __throw_system_error(EPERM, "shared_lock::unlock: not locked"); 409 __m_->unlock_shared(); 410 __owns_ = false; 411 } 412 413 template <class _Mutex> 414 inline _LIBCPP_INLINE_VISIBILITY 415 void 416 swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT 417 {__x.swap(__y);} 418 419 _LIBCPP_END_NAMESPACE_STD 420 421 #endif // !_LIBCPP_HAS_NO_THREADS 422 423 #endif // _LIBCPP_STD_VER > 11 424 425 #endif // _LIBCPP_SHARED_MUTEX 426