OLD | NEW |
(Empty) | |
| 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 |
| 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 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_tim
e); |
| 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_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_mutex(); |
| 128 _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default; |
| 129 |
| 130 shared_mutex(const shared_mutex&) = delete; |
| 131 shared_mutex& operator=(const shared_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_tim
e); |
| 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_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_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_reader
s_) |
| 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 mute
x"); |
| 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 nul
l mutex"); |
| 393 if (__owns_) |
| 394 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already lock
ed"); |
| 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 |
OLD | NEW |