blob: fbde0cf137a83f1db4de579af6b492aa9a0cbaa1 [file] [log] [blame]
Howard Hinnant6185ace2013-09-21 01:49:28 +00001// -*- 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
Marshall Clowac28c3d2015-06-30 14:04:14 +000022class shared_mutex // C++17
23{
24public:
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 void unlock();
35
36 // Shared ownership
37 void lock_shared(); // blocking
38 bool try_lock_shared();
39 void unlock_shared();
40
41 typedef implementation-defined native_handle_type; // See 30.2.3
42 native_handle_type native_handle(); // See 30.2.3
43};
44
David Majnemer10c8c362014-03-17 20:19:44 +000045class shared_timed_mutex
Howard Hinnant6185ace2013-09-21 01:49:28 +000046{
47public:
David Majnemer10c8c362014-03-17 20:19:44 +000048 shared_timed_mutex();
49 ~shared_timed_mutex();
Howard Hinnant6185ace2013-09-21 01:49:28 +000050
David Majnemer10c8c362014-03-17 20:19:44 +000051 shared_timed_mutex(const shared_timed_mutex&) = delete;
52 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
Howard Hinnant6185ace2013-09-21 01:49:28 +000053
54 // Exclusive ownership
55 void lock(); // blocking
56 bool try_lock();
57 template <class Rep, class Period>
58 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
59 template <class Clock, class Duration>
60 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
61 void unlock();
62
63 // Shared ownership
64 void lock_shared(); // blocking
65 bool try_lock_shared();
66 template <class Rep, class Period>
67 bool
68 try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
69 template <class Clock, class Duration>
70 bool
71 try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
72 void unlock_shared();
73};
74
75template <class Mutex>
76class shared_lock
77{
78public:
79 typedef Mutex mutex_type;
80
81 // Shared locking
82 shared_lock() noexcept;
83 explicit shared_lock(mutex_type& m); // blocking
84 shared_lock(mutex_type& m, defer_lock_t) noexcept;
85 shared_lock(mutex_type& m, try_to_lock_t);
86 shared_lock(mutex_type& m, adopt_lock_t);
87 template <class Clock, class Duration>
88 shared_lock(mutex_type& m,
89 const chrono::time_point<Clock, Duration>& abs_time);
90 template <class Rep, class Period>
91 shared_lock(mutex_type& m,
92 const chrono::duration<Rep, Period>& rel_time);
93 ~shared_lock();
94
95 shared_lock(shared_lock const&) = delete;
96 shared_lock& operator=(shared_lock const&) = delete;
97
98 shared_lock(shared_lock&& u) noexcept;
99 shared_lock& operator=(shared_lock&& u) noexcept;
100
101 void lock(); // blocking
102 bool try_lock();
103 template <class Rep, class Period>
104 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
105 template <class Clock, class Duration>
106 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
107 void unlock();
108
109 // Setters
110 void swap(shared_lock& u) noexcept;
111 mutex_type* release() noexcept;
112
113 // Getters
114 bool owns_lock() const noexcept;
115 explicit operator bool () const noexcept;
116 mutex_type* mutex() const noexcept;
117};
118
119template <class Mutex>
120 void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
121
122} // std
123
124*/
125
126#include <__config>
Marshall Clow0a1e7502018-09-12 19:41:40 +0000127#include <version>
Howard Hinnant6185ace2013-09-21 01:49:28 +0000128
Eric Fiselierf4433a32017-05-31 22:07:49 +0000129_LIBCPP_PUSH_MACROS
130#include <__undef_macros>
131
132
Louis Dionne5e0eadd2018-08-01 02:08:59 +0000133#if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_LIBRARY)
Howard Hinnant6185ace2013-09-21 01:49:28 +0000134
135#include <__mutex_base>
136
Howard Hinnant6185ace2013-09-21 01:49:28 +0000137#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
138#pragma GCC system_header
139#endif
140
Jonathan Roelofs39cb6bf2014-09-05 19:45:05 +0000141#ifdef _LIBCPP_HAS_NO_THREADS
142#error <shared_mutex> is not supported on this single threaded system
143#else // !_LIBCPP_HAS_NO_THREADS
144
Howard Hinnant6185ace2013-09-21 01:49:28 +0000145_LIBCPP_BEGIN_NAMESPACE_STD
146
Mehdi Amini228053d2017-05-04 17:08:54 +0000147struct _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX __shared_mutex_base
Howard Hinnant6185ace2013-09-21 01:49:28 +0000148{
149 mutex __mut_;
150 condition_variable __gate1_;
151 condition_variable __gate2_;
152 unsigned __state_;
153
154 static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
155 static const unsigned __n_readers_ = ~__write_entered_;
Marshall Clowac28c3d2015-06-30 14:04:14 +0000156
157 __shared_mutex_base();
158 _LIBCPP_INLINE_VISIBILITY ~__shared_mutex_base() = default;
159
160 __shared_mutex_base(const __shared_mutex_base&) = delete;
161 __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
162
163 // Exclusive ownership
164 void lock(); // blocking
165 bool try_lock();
166 void unlock();
167
168 // Shared ownership
169 void lock_shared(); // blocking
170 bool try_lock_shared();
171 void unlock_shared();
172
173// typedef implementation-defined native_handle_type; // See 30.2.3
174// native_handle_type native_handle(); // See 30.2.3
175};
176
177
178#if _LIBCPP_STD_VER > 14
Mehdi Amini228053d2017-05-04 17:08:54 +0000179class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_mutex
Marshall Clowac28c3d2015-06-30 14:04:14 +0000180{
Marshall Clow580b6e62017-03-24 03:40:36 +0000181 __shared_mutex_base __base;
Marshall Clowac28c3d2015-06-30 14:04:14 +0000182public:
Eric Fiselier26654172017-05-08 01:31:50 +0000183 _LIBCPP_INLINE_VISIBILITY shared_mutex() : __base() {}
Marshall Clowac28c3d2015-06-30 14:04:14 +0000184 _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default;
185
186 shared_mutex(const shared_mutex&) = delete;
187 shared_mutex& operator=(const shared_mutex&) = delete;
188
189 // Exclusive ownership
190 _LIBCPP_INLINE_VISIBILITY void lock() { return __base.lock(); }
191 _LIBCPP_INLINE_VISIBILITY bool try_lock() { return __base.try_lock(); }
192 _LIBCPP_INLINE_VISIBILITY void unlock() { return __base.unlock(); }
193
194 // Shared ownership
195 _LIBCPP_INLINE_VISIBILITY void lock_shared() { return __base.lock_shared(); }
196 _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() { return __base.try_lock_shared(); }
197 _LIBCPP_INLINE_VISIBILITY void unlock_shared() { return __base.unlock_shared(); }
198
199// typedef __shared_mutex_base::native_handle_type native_handle_type;
200// _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() { return __base::unlock_shared(); }
201};
202#endif
203
204
Mehdi Amini228053d2017-05-04 17:08:54 +0000205class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_timed_mutex
Marshall Clowac28c3d2015-06-30 14:04:14 +0000206{
Marshall Clow580b6e62017-03-24 03:40:36 +0000207 __shared_mutex_base __base;
Howard Hinnant6185ace2013-09-21 01:49:28 +0000208public:
David Majnemer10c8c362014-03-17 20:19:44 +0000209 shared_timed_mutex();
210 _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
Howard Hinnant6185ace2013-09-21 01:49:28 +0000211
David Majnemer10c8c362014-03-17 20:19:44 +0000212 shared_timed_mutex(const shared_timed_mutex&) = delete;
213 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
Howard Hinnant6185ace2013-09-21 01:49:28 +0000214
215 // Exclusive ownership
216 void lock();
217 bool try_lock();
218 template <class _Rep, class _Period>
219 _LIBCPP_INLINE_VISIBILITY
220 bool
221 try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
222 {
223 return try_lock_until(chrono::steady_clock::now() + __rel_time);
224 }
225 template <class _Clock, class _Duration>
Shoaib Meenai55f3a462017-03-02 03:22:18 +0000226 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
Howard Hinnant6185ace2013-09-21 01:49:28 +0000227 bool
228 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
229 void unlock();
230
231 // Shared ownership
232 void lock_shared();
233 bool try_lock_shared();
234 template <class _Rep, class _Period>
235 _LIBCPP_INLINE_VISIBILITY
236 bool
237 try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
238 {
239 return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
240 }
241 template <class _Clock, class _Duration>
Shoaib Meenai55f3a462017-03-02 03:22:18 +0000242 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
Howard Hinnant6185ace2013-09-21 01:49:28 +0000243 bool
244 try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
245 void unlock_shared();
246};
247
248template <class _Clock, class _Duration>
249bool
David Majnemer10c8c362014-03-17 20:19:44 +0000250shared_timed_mutex::try_lock_until(
Howard Hinnant6185ace2013-09-21 01:49:28 +0000251 const chrono::time_point<_Clock, _Duration>& __abs_time)
252{
Marshall Clowac28c3d2015-06-30 14:04:14 +0000253 unique_lock<mutex> __lk(__base.__mut_);
254 if (__base.__state_ & __base.__write_entered_)
Howard Hinnant6185ace2013-09-21 01:49:28 +0000255 {
256 while (true)
257 {
Marshall Clowac28c3d2015-06-30 14:04:14 +0000258 cv_status __status = __base.__gate1_.wait_until(__lk, __abs_time);
259 if ((__base.__state_ & __base.__write_entered_) == 0)
Howard Hinnant6185ace2013-09-21 01:49:28 +0000260 break;
261 if (__status == cv_status::timeout)
262 return false;
263 }
264 }
Marshall Clowac28c3d2015-06-30 14:04:14 +0000265 __base.__state_ |= __base.__write_entered_;
266 if (__base.__state_ & __base.__n_readers_)
Howard Hinnant6185ace2013-09-21 01:49:28 +0000267 {
268 while (true)
269 {
Marshall Clowac28c3d2015-06-30 14:04:14 +0000270 cv_status __status = __base.__gate2_.wait_until(__lk, __abs_time);
271 if ((__base.__state_ & __base.__n_readers_) == 0)
Howard Hinnant6185ace2013-09-21 01:49:28 +0000272 break;
273 if (__status == cv_status::timeout)
274 {
Marshall Clowac28c3d2015-06-30 14:04:14 +0000275 __base.__state_ &= ~__base.__write_entered_;
276 __base.__gate1_.notify_all();
Howard Hinnant6185ace2013-09-21 01:49:28 +0000277 return false;
278 }
279 }
280 }
281 return true;
282}
283
284template <class _Clock, class _Duration>
285bool
David Majnemer10c8c362014-03-17 20:19:44 +0000286shared_timed_mutex::try_lock_shared_until(
Howard Hinnant6185ace2013-09-21 01:49:28 +0000287 const chrono::time_point<_Clock, _Duration>& __abs_time)
288{
Marshall Clowac28c3d2015-06-30 14:04:14 +0000289 unique_lock<mutex> __lk(__base.__mut_);
290 if ((__base.__state_ & __base.__write_entered_) || (__base.__state_ & __base.__n_readers_) == __base.__n_readers_)
Howard Hinnant6185ace2013-09-21 01:49:28 +0000291 {
292 while (true)
293 {
Marshall Clowac28c3d2015-06-30 14:04:14 +0000294 cv_status status = __base.__gate1_.wait_until(__lk, __abs_time);
295 if ((__base.__state_ & __base.__write_entered_) == 0 &&
296 (__base.__state_ & __base.__n_readers_) < __base.__n_readers_)
Howard Hinnant6185ace2013-09-21 01:49:28 +0000297 break;
298 if (status == cv_status::timeout)
299 return false;
300 }
301 }
Marshall Clowac28c3d2015-06-30 14:04:14 +0000302 unsigned __num_readers = (__base.__state_ & __base.__n_readers_) + 1;
303 __base.__state_ &= ~__base.__n_readers_;
304 __base.__state_ |= __num_readers;
Howard Hinnant6185ace2013-09-21 01:49:28 +0000305 return true;
306}
307
308template <class _Mutex>
309class shared_lock
310{
311public:
312 typedef _Mutex mutex_type;
313
314private:
315 mutex_type* __m_;
316 bool __owns_;
317
318public:
319 _LIBCPP_INLINE_VISIBILITY
Marshall Clowdf4053a2014-08-25 14:53:16 +0000320 shared_lock() _NOEXCEPT
Howard Hinnant6185ace2013-09-21 01:49:28 +0000321 : __m_(nullptr),
322 __owns_(false)
323 {}
324
325 _LIBCPP_INLINE_VISIBILITY
326 explicit shared_lock(mutex_type& __m)
Marshall Clow24ddc252016-04-13 17:02:23 +0000327 : __m_(_VSTD::addressof(__m)),
Howard Hinnant6185ace2013-09-21 01:49:28 +0000328 __owns_(true)
329 {__m_->lock_shared();}
330
331 _LIBCPP_INLINE_VISIBILITY
Marshall Clowdf4053a2014-08-25 14:53:16 +0000332 shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
Marshall Clow24ddc252016-04-13 17:02:23 +0000333 : __m_(_VSTD::addressof(__m)),
Howard Hinnant6185ace2013-09-21 01:49:28 +0000334 __owns_(false)
335 {}
336
337 _LIBCPP_INLINE_VISIBILITY
338 shared_lock(mutex_type& __m, try_to_lock_t)
Marshall Clow24ddc252016-04-13 17:02:23 +0000339 : __m_(_VSTD::addressof(__m)),
Howard Hinnant6185ace2013-09-21 01:49:28 +0000340 __owns_(__m.try_lock_shared())
341 {}
342
343 _LIBCPP_INLINE_VISIBILITY
344 shared_lock(mutex_type& __m, adopt_lock_t)
Marshall Clow24ddc252016-04-13 17:02:23 +0000345 : __m_(_VSTD::addressof(__m)),
Howard Hinnant6185ace2013-09-21 01:49:28 +0000346 __owns_(true)
347 {}
348
349 template <class _Clock, class _Duration>
350 _LIBCPP_INLINE_VISIBILITY
351 shared_lock(mutex_type& __m,
352 const chrono::time_point<_Clock, _Duration>& __abs_time)
Marshall Clow24ddc252016-04-13 17:02:23 +0000353 : __m_(_VSTD::addressof(__m)),
Howard Hinnant6185ace2013-09-21 01:49:28 +0000354 __owns_(__m.try_lock_shared_until(__abs_time))
355 {}
356
357 template <class _Rep, class _Period>
358 _LIBCPP_INLINE_VISIBILITY
359 shared_lock(mutex_type& __m,
360 const chrono::duration<_Rep, _Period>& __rel_time)
Marshall Clow24ddc252016-04-13 17:02:23 +0000361 : __m_(_VSTD::addressof(__m)),
Howard Hinnant6185ace2013-09-21 01:49:28 +0000362 __owns_(__m.try_lock_shared_for(__rel_time))
363 {}
364
365 _LIBCPP_INLINE_VISIBILITY
366 ~shared_lock()
367 {
368 if (__owns_)
369 __m_->unlock_shared();
370 }
371
372 shared_lock(shared_lock const&) = delete;
373 shared_lock& operator=(shared_lock const&) = delete;
374
375 _LIBCPP_INLINE_VISIBILITY
Marshall Clowdf4053a2014-08-25 14:53:16 +0000376 shared_lock(shared_lock&& __u) _NOEXCEPT
Howard Hinnant6185ace2013-09-21 01:49:28 +0000377 : __m_(__u.__m_),
378 __owns_(__u.__owns_)
379 {
380 __u.__m_ = nullptr;
381 __u.__owns_ = false;
382 }
383
384 _LIBCPP_INLINE_VISIBILITY
Marshall Clowdf4053a2014-08-25 14:53:16 +0000385 shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
Howard Hinnant6185ace2013-09-21 01:49:28 +0000386 {
387 if (__owns_)
388 __m_->unlock_shared();
389 __m_ = nullptr;
390 __owns_ = false;
391 __m_ = __u.__m_;
392 __owns_ = __u.__owns_;
393 __u.__m_ = nullptr;
394 __u.__owns_ = false;
395 return *this;
396 }
397
398 void lock();
399 bool try_lock();
400 template <class Rep, class Period>
401 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
402 template <class Clock, class Duration>
403 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
404 void unlock();
405
406 // Setters
407 _LIBCPP_INLINE_VISIBILITY
Marshall Clowdf4053a2014-08-25 14:53:16 +0000408 void swap(shared_lock& __u) _NOEXCEPT
Howard Hinnant6185ace2013-09-21 01:49:28 +0000409 {
410 _VSTD::swap(__m_, __u.__m_);
411 _VSTD::swap(__owns_, __u.__owns_);
412 }
413
414 _LIBCPP_INLINE_VISIBILITY
Marshall Clowdf4053a2014-08-25 14:53:16 +0000415 mutex_type* release() _NOEXCEPT
Howard Hinnant6185ace2013-09-21 01:49:28 +0000416 {
417 mutex_type* __m = __m_;
418 __m_ = nullptr;
419 __owns_ = false;
420 return __m;
421 }
422
423 // Getters
424 _LIBCPP_INLINE_VISIBILITY
Marshall Clowdf4053a2014-08-25 14:53:16 +0000425 bool owns_lock() const _NOEXCEPT {return __owns_;}
Howard Hinnant6185ace2013-09-21 01:49:28 +0000426
427 _LIBCPP_INLINE_VISIBILITY
Marshall Clowdf4053a2014-08-25 14:53:16 +0000428 explicit operator bool () const _NOEXCEPT {return __owns_;}
Howard Hinnant6185ace2013-09-21 01:49:28 +0000429
430 _LIBCPP_INLINE_VISIBILITY
Marshall Clowdf4053a2014-08-25 14:53:16 +0000431 mutex_type* mutex() const _NOEXCEPT {return __m_;}
Howard Hinnant6185ace2013-09-21 01:49:28 +0000432};
433
434template <class _Mutex>
435void
436shared_lock<_Mutex>::lock()
437{
438 if (__m_ == nullptr)
439 __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
440 if (__owns_)
441 __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
442 __m_->lock_shared();
443 __owns_ = true;
444}
445
446template <class _Mutex>
447bool
448shared_lock<_Mutex>::try_lock()
449{
450 if (__m_ == nullptr)
451 __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
452 if (__owns_)
453 __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
454 __owns_ = __m_->try_lock_shared();
455 return __owns_;
456}
457
458template <class _Mutex>
459template <class _Rep, class _Period>
460bool
461shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
462{
463 if (__m_ == nullptr)
464 __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
465 if (__owns_)
466 __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
467 __owns_ = __m_->try_lock_shared_for(__d);
468 return __owns_;
469}
470
471template <class _Mutex>
472template <class _Clock, class _Duration>
473bool
474shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
475{
476 if (__m_ == nullptr)
477 __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
478 if (__owns_)
479 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
480 __owns_ = __m_->try_lock_shared_until(__t);
481 return __owns_;
482}
483
484template <class _Mutex>
485void
486shared_lock<_Mutex>::unlock()
487{
488 if (!__owns_)
489 __throw_system_error(EPERM, "shared_lock::unlock: not locked");
490 __m_->unlock_shared();
491 __owns_ = false;
492}
493
494template <class _Mutex>
495inline _LIBCPP_INLINE_VISIBILITY
496void
Marshall Clowdf4053a2014-08-25 14:53:16 +0000497swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
Howard Hinnant6185ace2013-09-21 01:49:28 +0000498 {__x.swap(__y);}
499
500_LIBCPP_END_NAMESPACE_STD
501
Jonathan Roelofs39cb6bf2014-09-05 19:45:05 +0000502#endif // !_LIBCPP_HAS_NO_THREADS
503
Howard Hinnant6185ace2013-09-21 01:49:28 +0000504#endif // _LIBCPP_STD_VER > 11
505
Eric Fiselierf4433a32017-05-31 22:07:49 +0000506_LIBCPP_POP_MACROS
507
Howard Hinnant6185ace2013-09-21 01:49:28 +0000508#endif // _LIBCPP_SHARED_MUTEX