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 _LIBCPP_BEGIN_NAMESPACE_STD 116 117 class _LIBCPP_TYPE_VIS shared_timed_mutex 118 { 119 mutex __mut_; 120 condition_variable __gate1_; 121 condition_variable __gate2_; 122 unsigned __state_; 123 124 static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1); 125 static const unsigned __n_readers_ = ~__write_entered_; 126 public: 127 shared_timed_mutex(); 128 _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default; 129 130 shared_timed_mutex(const shared_timed_mutex&) = delete; 131 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete; 132 133 // Exclusive ownership 134 void lock(); 135 bool try_lock(); 136 template <class _Rep, class _Period> 137 _LIBCPP_INLINE_VISIBILITY 138 bool 139 try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time) 140 { 141 return try_lock_until(chrono::steady_clock::now() + __rel_time); 142 } 143 template <class _Clock, class _Duration> 144 bool 145 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time); 146 void unlock(); 147 148 // Shared ownership 149 void lock_shared(); 150 bool try_lock_shared(); 151 template <class _Rep, class _Period> 152 _LIBCPP_INLINE_VISIBILITY 153 bool 154 try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time) 155 { 156 return try_lock_shared_until(chrono::steady_clock::now() + __rel_time); 157 } 158 template <class _Clock, class _Duration> 159 bool 160 try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time); 161 void unlock_shared(); 162 }; 163 164 template <class _Clock, class _Duration> 165 bool 166 shared_timed_mutex::try_lock_until( 167 const chrono::time_point<_Clock, _Duration>& __abs_time) 168 { 169 unique_lock<mutex> __lk(__mut_); 170 if (__state_ & __write_entered_) 171 { 172 while (true) 173 { 174 cv_status __status = __gate1_.wait_until(__lk, __abs_time); 175 if ((__state_ & __write_entered_) == 0) 176 break; 177 if (__status == cv_status::timeout) 178 return false; 179 } 180 } 181 __state_ |= __write_entered_; 182 if (__state_ & __n_readers_) 183 { 184 while (true) 185 { 186 cv_status __status = __gate2_.wait_until(__lk, __abs_time); 187 if ((__state_ & __n_readers_) == 0) 188 break; 189 if (__status == cv_status::timeout) 190 { 191 __state_ &= ~__write_entered_; 192 return false; 193 } 194 } 195 } 196 return true; 197 } 198 199 template <class _Clock, class _Duration> 200 bool 201 shared_timed_mutex::try_lock_shared_until( 202 const chrono::time_point<_Clock, _Duration>& __abs_time) 203 { 204 unique_lock<mutex> __lk(__mut_); 205 if ((__state_ & __write_entered_) || (__state_ & __n_readers_) == __n_readers_) 206 { 207 while (true) 208 { 209 cv_status status = __gate1_.wait_until(__lk, __abs_time); 210 if ((__state_ & __write_entered_) == 0 && 211 (__state_ & __n_readers_) < __n_readers_) 212 break; 213 if (status == cv_status::timeout) 214 return false; 215 } 216 } 217 unsigned __num_readers = (__state_ & __n_readers_) + 1; 218 __state_ &= ~__n_readers_; 219 __state_ |= __num_readers; 220 return true; 221 } 222 223 template <class _Mutex> 224 class shared_lock 225 { 226 public: 227 typedef _Mutex mutex_type; 228 229 private: 230 mutex_type* __m_; 231 bool __owns_; 232 233 public: 234 _LIBCPP_INLINE_VISIBILITY 235 shared_lock() noexcept 236 : __m_(nullptr), 237 __owns_(false) 238 {} 239 240 _LIBCPP_INLINE_VISIBILITY 241 explicit shared_lock(mutex_type& __m) 242 : __m_(&__m), 243 __owns_(true) 244 {__m_->lock_shared();} 245 246 _LIBCPP_INLINE_VISIBILITY 247 shared_lock(mutex_type& __m, defer_lock_t) noexcept 248 : __m_(&__m), 249 __owns_(false) 250 {} 251 252 _LIBCPP_INLINE_VISIBILITY 253 shared_lock(mutex_type& __m, try_to_lock_t) 254 : __m_(&__m), 255 __owns_(__m.try_lock_shared()) 256 {} 257 258 _LIBCPP_INLINE_VISIBILITY 259 shared_lock(mutex_type& __m, adopt_lock_t) 260 : __m_(&__m), 261 __owns_(true) 262 {} 263 264 template <class _Clock, class _Duration> 265 _LIBCPP_INLINE_VISIBILITY 266 shared_lock(mutex_type& __m, 267 const chrono::time_point<_Clock, _Duration>& __abs_time) 268 : __m_(&__m), 269 __owns_(__m.try_lock_shared_until(__abs_time)) 270 {} 271 272 template <class _Rep, class _Period> 273 _LIBCPP_INLINE_VISIBILITY 274 shared_lock(mutex_type& __m, 275 const chrono::duration<_Rep, _Period>& __rel_time) 276 : __m_(&__m), 277 __owns_(__m.try_lock_shared_for(__rel_time)) 278 {} 279 280 _LIBCPP_INLINE_VISIBILITY 281 ~shared_lock() 282 { 283 if (__owns_) 284 __m_->unlock_shared(); 285 } 286 287 shared_lock(shared_lock const&) = delete; 288 shared_lock& operator=(shared_lock const&) = delete; 289 290 _LIBCPP_INLINE_VISIBILITY 291 shared_lock(shared_lock&& __u) noexcept 292 : __m_(__u.__m_), 293 __owns_(__u.__owns_) 294 { 295 __u.__m_ = nullptr; 296 __u.__owns_ = false; 297 } 298 299 _LIBCPP_INLINE_VISIBILITY 300 shared_lock& operator=(shared_lock&& __u) noexcept 301 { 302 if (__owns_) 303 __m_->unlock_shared(); 304 __m_ = nullptr; 305 __owns_ = false; 306 __m_ = __u.__m_; 307 __owns_ = __u.__owns_; 308 __u.__m_ = nullptr; 309 __u.__owns_ = false; 310 return *this; 311 } 312 313 void lock(); 314 bool try_lock(); 315 template <class Rep, class Period> 316 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); 317 template <class Clock, class Duration> 318 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); 319 void unlock(); 320 321 // Setters 322 _LIBCPP_INLINE_VISIBILITY 323 void swap(shared_lock& __u) noexcept 324 { 325 _VSTD::swap(__m_, __u.__m_); 326 _VSTD::swap(__owns_, __u.__owns_); 327 } 328 329 _LIBCPP_INLINE_VISIBILITY 330 mutex_type* release() noexcept 331 { 332 mutex_type* __m = __m_; 333 __m_ = nullptr; 334 __owns_ = false; 335 return __m; 336 } 337 338 // Getters 339 _LIBCPP_INLINE_VISIBILITY 340 bool owns_lock() const noexcept {return __owns_;} 341 342 _LIBCPP_INLINE_VISIBILITY 343 explicit operator bool () const noexcept {return __owns_;} 344 345 _LIBCPP_INLINE_VISIBILITY 346 mutex_type* mutex() const noexcept {return __m_;} 347 }; 348 349 template <class _Mutex> 350 void 351 shared_lock<_Mutex>::lock() 352 { 353 if (__m_ == nullptr) 354 __throw_system_error(EPERM, "shared_lock::lock: references null mutex"); 355 if (__owns_) 356 __throw_system_error(EDEADLK, "shared_lock::lock: already locked"); 357 __m_->lock_shared(); 358 __owns_ = true; 359 } 360 361 template <class _Mutex> 362 bool 363 shared_lock<_Mutex>::try_lock() 364 { 365 if (__m_ == nullptr) 366 __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex"); 367 if (__owns_) 368 __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked"); 369 __owns_ = __m_->try_lock_shared(); 370 return __owns_; 371 } 372 373 template <class _Mutex> 374 template <class _Rep, class _Period> 375 bool 376 shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d) 377 { 378 if (__m_ == nullptr) 379 __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex"); 380 if (__owns_) 381 __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked"); 382 __owns_ = __m_->try_lock_shared_for(__d); 383 return __owns_; 384 } 385 386 template <class _Mutex> 387 template <class _Clock, class _Duration> 388 bool 389 shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) 390 { 391 if (__m_ == nullptr) 392 __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex"); 393 if (__owns_) 394 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked"); 395 __owns_ = __m_->try_lock_shared_until(__t); 396 return __owns_; 397 } 398 399 template <class _Mutex> 400 void 401 shared_lock<_Mutex>::unlock() 402 { 403 if (!__owns_) 404 __throw_system_error(EPERM, "shared_lock::unlock: not locked"); 405 __m_->unlock_shared(); 406 __owns_ = false; 407 } 408 409 template <class _Mutex> 410 inline _LIBCPP_INLINE_VISIBILITY 411 void 412 swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) noexcept 413 {__x.swap(__y);} 414 415 _LIBCPP_END_NAMESPACE_STD 416 417 #endif // _LIBCPP_STD_VER > 11 418 419 #endif // _LIBCPP_SHARED_MUTEX 420