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