blob: f2fd667b5c67c6fa865f726f1ab60e56f6939b7e [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>
127
128#if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_SHARED_MUTEX)
129
130#include <__mutex_base>
131
132#include <__undef_min_max>
133
134#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
135#pragma GCC system_header
136#endif
137
Jonathan Roelofs39cb6bf2014-09-05 19:45:05 +0000138#ifdef _LIBCPP_HAS_NO_THREADS
139#error <shared_mutex> is not supported on this single threaded system
140#else // !_LIBCPP_HAS_NO_THREADS
141
Howard Hinnant6185ace2013-09-21 01:49:28 +0000142_LIBCPP_BEGIN_NAMESPACE_STD
143
Marshall Clowac28c3d2015-06-30 14:04:14 +0000144struct _LIBCPP_TYPE_VIS __shared_mutex_base
Howard Hinnant6185ace2013-09-21 01:49:28 +0000145{
146 mutex __mut_;
147 condition_variable __gate1_;
148 condition_variable __gate2_;
149 unsigned __state_;
150
151 static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
152 static const unsigned __n_readers_ = ~__write_entered_;
Marshall Clowac28c3d2015-06-30 14:04:14 +0000153
154 __shared_mutex_base();
155 _LIBCPP_INLINE_VISIBILITY ~__shared_mutex_base() = default;
156
157 __shared_mutex_base(const __shared_mutex_base&) = delete;
158 __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
159
160 // Exclusive ownership
161 void lock(); // blocking
162 bool try_lock();
163 void unlock();
164
165 // Shared ownership
166 void lock_shared(); // blocking
167 bool try_lock_shared();
168 void unlock_shared();
169
170// typedef implementation-defined native_handle_type; // See 30.2.3
171// native_handle_type native_handle(); // See 30.2.3
172};
173
174
175#if _LIBCPP_STD_VER > 14
176class _LIBCPP_TYPE_VIS shared_mutex
177{
Marshall Clow580b6e62017-03-24 03:40:36 +0000178 __shared_mutex_base __base;
Marshall Clowac28c3d2015-06-30 14:04:14 +0000179public:
180 shared_mutex() : __base() {}
181 _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default;
182
183 shared_mutex(const shared_mutex&) = delete;
184 shared_mutex& operator=(const shared_mutex&) = delete;
185
186 // Exclusive ownership
187 _LIBCPP_INLINE_VISIBILITY void lock() { return __base.lock(); }
188 _LIBCPP_INLINE_VISIBILITY bool try_lock() { return __base.try_lock(); }
189 _LIBCPP_INLINE_VISIBILITY void unlock() { return __base.unlock(); }
190
191 // Shared ownership
192 _LIBCPP_INLINE_VISIBILITY void lock_shared() { return __base.lock_shared(); }
193 _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() { return __base.try_lock_shared(); }
194 _LIBCPP_INLINE_VISIBILITY void unlock_shared() { return __base.unlock_shared(); }
195
196// typedef __shared_mutex_base::native_handle_type native_handle_type;
197// _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() { return __base::unlock_shared(); }
198};
199#endif
200
201
202class _LIBCPP_TYPE_VIS shared_timed_mutex
203{
Marshall Clow580b6e62017-03-24 03:40:36 +0000204 __shared_mutex_base __base;
Howard Hinnant6185ace2013-09-21 01:49:28 +0000205public:
David Majnemer10c8c362014-03-17 20:19:44 +0000206 shared_timed_mutex();
207 _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
Howard Hinnant6185ace2013-09-21 01:49:28 +0000208
David Majnemer10c8c362014-03-17 20:19:44 +0000209 shared_timed_mutex(const shared_timed_mutex&) = delete;
210 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
Howard Hinnant6185ace2013-09-21 01:49:28 +0000211
212 // Exclusive ownership
213 void lock();
214 bool try_lock();
215 template <class _Rep, class _Period>
216 _LIBCPP_INLINE_VISIBILITY
217 bool
218 try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
219 {
220 return try_lock_until(chrono::steady_clock::now() + __rel_time);
221 }
222 template <class _Clock, class _Duration>
Shoaib Meenai55f3a462017-03-02 03:22:18 +0000223 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
Howard Hinnant6185ace2013-09-21 01:49:28 +0000224 bool
225 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
226 void unlock();
227
228 // Shared ownership
229 void lock_shared();
230 bool try_lock_shared();
231 template <class _Rep, class _Period>
232 _LIBCPP_INLINE_VISIBILITY
233 bool
234 try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
235 {
236 return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
237 }
238 template <class _Clock, class _Duration>
Shoaib Meenai55f3a462017-03-02 03:22:18 +0000239 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
Howard Hinnant6185ace2013-09-21 01:49:28 +0000240 bool
241 try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
242 void unlock_shared();
243};
244
245template <class _Clock, class _Duration>
246bool
David Majnemer10c8c362014-03-17 20:19:44 +0000247shared_timed_mutex::try_lock_until(
Howard Hinnant6185ace2013-09-21 01:49:28 +0000248 const chrono::time_point<_Clock, _Duration>& __abs_time)
249{
Marshall Clowac28c3d2015-06-30 14:04:14 +0000250 unique_lock<mutex> __lk(__base.__mut_);
251 if (__base.__state_ & __base.__write_entered_)
Howard Hinnant6185ace2013-09-21 01:49:28 +0000252 {
253 while (true)
254 {
Marshall Clowac28c3d2015-06-30 14:04:14 +0000255 cv_status __status = __base.__gate1_.wait_until(__lk, __abs_time);
256 if ((__base.__state_ & __base.__write_entered_) == 0)
Howard Hinnant6185ace2013-09-21 01:49:28 +0000257 break;
258 if (__status == cv_status::timeout)
259 return false;
260 }
261 }
Marshall Clowac28c3d2015-06-30 14:04:14 +0000262 __base.__state_ |= __base.__write_entered_;
263 if (__base.__state_ & __base.__n_readers_)
Howard Hinnant6185ace2013-09-21 01:49:28 +0000264 {
265 while (true)
266 {
Marshall Clowac28c3d2015-06-30 14:04:14 +0000267 cv_status __status = __base.__gate2_.wait_until(__lk, __abs_time);
268 if ((__base.__state_ & __base.__n_readers_) == 0)
Howard Hinnant6185ace2013-09-21 01:49:28 +0000269 break;
270 if (__status == cv_status::timeout)
271 {
Marshall Clowac28c3d2015-06-30 14:04:14 +0000272 __base.__state_ &= ~__base.__write_entered_;
273 __base.__gate1_.notify_all();
Howard Hinnant6185ace2013-09-21 01:49:28 +0000274 return false;
275 }
276 }
277 }
278 return true;
279}
280
281template <class _Clock, class _Duration>
282bool
David Majnemer10c8c362014-03-17 20:19:44 +0000283shared_timed_mutex::try_lock_shared_until(
Howard Hinnant6185ace2013-09-21 01:49:28 +0000284 const chrono::time_point<_Clock, _Duration>& __abs_time)
285{
Marshall Clowac28c3d2015-06-30 14:04:14 +0000286 unique_lock<mutex> __lk(__base.__mut_);
287 if ((__base.__state_ & __base.__write_entered_) || (__base.__state_ & __base.__n_readers_) == __base.__n_readers_)
Howard Hinnant6185ace2013-09-21 01:49:28 +0000288 {
289 while (true)
290 {
Marshall Clowac28c3d2015-06-30 14:04:14 +0000291 cv_status status = __base.__gate1_.wait_until(__lk, __abs_time);
292 if ((__base.__state_ & __base.__write_entered_) == 0 &&
293 (__base.__state_ & __base.__n_readers_) < __base.__n_readers_)
Howard Hinnant6185ace2013-09-21 01:49:28 +0000294 break;
295 if (status == cv_status::timeout)
296 return false;
297 }
298 }
Marshall Clowac28c3d2015-06-30 14:04:14 +0000299 unsigned __num_readers = (__base.__state_ & __base.__n_readers_) + 1;
300 __base.__state_ &= ~__base.__n_readers_;
301 __base.__state_ |= __num_readers;
Howard Hinnant6185ace2013-09-21 01:49:28 +0000302 return true;
303}
304
305template <class _Mutex>
306class shared_lock
307{
308public:
309 typedef _Mutex mutex_type;
310
311private:
312 mutex_type* __m_;
313 bool __owns_;
314
315public:
316 _LIBCPP_INLINE_VISIBILITY
Marshall Clowdf4053a2014-08-25 14:53:16 +0000317 shared_lock() _NOEXCEPT
Howard Hinnant6185ace2013-09-21 01:49:28 +0000318 : __m_(nullptr),
319 __owns_(false)
320 {}
321
322 _LIBCPP_INLINE_VISIBILITY
323 explicit shared_lock(mutex_type& __m)
Marshall Clow24ddc252016-04-13 17:02:23 +0000324 : __m_(_VSTD::addressof(__m)),
Howard Hinnant6185ace2013-09-21 01:49:28 +0000325 __owns_(true)
326 {__m_->lock_shared();}
327
328 _LIBCPP_INLINE_VISIBILITY
Marshall Clowdf4053a2014-08-25 14:53:16 +0000329 shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
Marshall Clow24ddc252016-04-13 17:02:23 +0000330 : __m_(_VSTD::addressof(__m)),
Howard Hinnant6185ace2013-09-21 01:49:28 +0000331 __owns_(false)
332 {}
333
334 _LIBCPP_INLINE_VISIBILITY
335 shared_lock(mutex_type& __m, try_to_lock_t)
Marshall Clow24ddc252016-04-13 17:02:23 +0000336 : __m_(_VSTD::addressof(__m)),
Howard Hinnant6185ace2013-09-21 01:49:28 +0000337 __owns_(__m.try_lock_shared())
338 {}
339
340 _LIBCPP_INLINE_VISIBILITY
341 shared_lock(mutex_type& __m, adopt_lock_t)
Marshall Clow24ddc252016-04-13 17:02:23 +0000342 : __m_(_VSTD::addressof(__m)),
Howard Hinnant6185ace2013-09-21 01:49:28 +0000343 __owns_(true)
344 {}
345
346 template <class _Clock, class _Duration>
347 _LIBCPP_INLINE_VISIBILITY
348 shared_lock(mutex_type& __m,
349 const chrono::time_point<_Clock, _Duration>& __abs_time)
Marshall Clow24ddc252016-04-13 17:02:23 +0000350 : __m_(_VSTD::addressof(__m)),
Howard Hinnant6185ace2013-09-21 01:49:28 +0000351 __owns_(__m.try_lock_shared_until(__abs_time))
352 {}
353
354 template <class _Rep, class _Period>
355 _LIBCPP_INLINE_VISIBILITY
356 shared_lock(mutex_type& __m,
357 const chrono::duration<_Rep, _Period>& __rel_time)
Marshall Clow24ddc252016-04-13 17:02:23 +0000358 : __m_(_VSTD::addressof(__m)),
Howard Hinnant6185ace2013-09-21 01:49:28 +0000359 __owns_(__m.try_lock_shared_for(__rel_time))
360 {}
361
362 _LIBCPP_INLINE_VISIBILITY
363 ~shared_lock()
364 {
365 if (__owns_)
366 __m_->unlock_shared();
367 }
368
369 shared_lock(shared_lock const&) = delete;
370 shared_lock& operator=(shared_lock const&) = delete;
371
372 _LIBCPP_INLINE_VISIBILITY
Marshall Clowdf4053a2014-08-25 14:53:16 +0000373 shared_lock(shared_lock&& __u) _NOEXCEPT
Howard Hinnant6185ace2013-09-21 01:49:28 +0000374 : __m_(__u.__m_),
375 __owns_(__u.__owns_)
376 {
377 __u.__m_ = nullptr;
378 __u.__owns_ = false;
379 }
380
381 _LIBCPP_INLINE_VISIBILITY
Marshall Clowdf4053a2014-08-25 14:53:16 +0000382 shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
Howard Hinnant6185ace2013-09-21 01:49:28 +0000383 {
384 if (__owns_)
385 __m_->unlock_shared();
386 __m_ = nullptr;
387 __owns_ = false;
388 __m_ = __u.__m_;
389 __owns_ = __u.__owns_;
390 __u.__m_ = nullptr;
391 __u.__owns_ = false;
392 return *this;
393 }
394
395 void lock();
396 bool try_lock();
397 template <class Rep, class Period>
398 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
399 template <class Clock, class Duration>
400 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
401 void unlock();
402
403 // Setters
404 _LIBCPP_INLINE_VISIBILITY
Marshall Clowdf4053a2014-08-25 14:53:16 +0000405 void swap(shared_lock& __u) _NOEXCEPT
Howard Hinnant6185ace2013-09-21 01:49:28 +0000406 {
407 _VSTD::swap(__m_, __u.__m_);
408 _VSTD::swap(__owns_, __u.__owns_);
409 }
410
411 _LIBCPP_INLINE_VISIBILITY
Marshall Clowdf4053a2014-08-25 14:53:16 +0000412 mutex_type* release() _NOEXCEPT
Howard Hinnant6185ace2013-09-21 01:49:28 +0000413 {
414 mutex_type* __m = __m_;
415 __m_ = nullptr;
416 __owns_ = false;
417 return __m;
418 }
419
420 // Getters
421 _LIBCPP_INLINE_VISIBILITY
Marshall Clowdf4053a2014-08-25 14:53:16 +0000422 bool owns_lock() const _NOEXCEPT {return __owns_;}
Howard Hinnant6185ace2013-09-21 01:49:28 +0000423
424 _LIBCPP_INLINE_VISIBILITY
Marshall Clowdf4053a2014-08-25 14:53:16 +0000425 explicit operator bool () const _NOEXCEPT {return __owns_;}
Howard Hinnant6185ace2013-09-21 01:49:28 +0000426
427 _LIBCPP_INLINE_VISIBILITY
Marshall Clowdf4053a2014-08-25 14:53:16 +0000428 mutex_type* mutex() const _NOEXCEPT {return __m_;}
Howard Hinnant6185ace2013-09-21 01:49:28 +0000429};
430
431template <class _Mutex>
432void
433shared_lock<_Mutex>::lock()
434{
435 if (__m_ == nullptr)
436 __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
437 if (__owns_)
438 __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
439 __m_->lock_shared();
440 __owns_ = true;
441}
442
443template <class _Mutex>
444bool
445shared_lock<_Mutex>::try_lock()
446{
447 if (__m_ == nullptr)
448 __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
449 if (__owns_)
450 __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
451 __owns_ = __m_->try_lock_shared();
452 return __owns_;
453}
454
455template <class _Mutex>
456template <class _Rep, class _Period>
457bool
458shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
459{
460 if (__m_ == nullptr)
461 __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
462 if (__owns_)
463 __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
464 __owns_ = __m_->try_lock_shared_for(__d);
465 return __owns_;
466}
467
468template <class _Mutex>
469template <class _Clock, class _Duration>
470bool
471shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
472{
473 if (__m_ == nullptr)
474 __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
475 if (__owns_)
476 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
477 __owns_ = __m_->try_lock_shared_until(__t);
478 return __owns_;
479}
480
481template <class _Mutex>
482void
483shared_lock<_Mutex>::unlock()
484{
485 if (!__owns_)
486 __throw_system_error(EPERM, "shared_lock::unlock: not locked");
487 __m_->unlock_shared();
488 __owns_ = false;
489}
490
491template <class _Mutex>
492inline _LIBCPP_INLINE_VISIBILITY
493void
Marshall Clowdf4053a2014-08-25 14:53:16 +0000494swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
Howard Hinnant6185ace2013-09-21 01:49:28 +0000495 {__x.swap(__y);}
496
497_LIBCPP_END_NAMESPACE_STD
498
Jonathan Roelofs39cb6bf2014-09-05 19:45:05 +0000499#endif // !_LIBCPP_HAS_NO_THREADS
500
Howard Hinnant6185ace2013-09-21 01:49:28 +0000501#endif // _LIBCPP_STD_VER > 11
502
503#endif // _LIBCPP_SHARED_MUTEX