blob: a7735d6732c581bb685a0e1e188a3fe23d3d1bb8 [file] [log] [blame]
Howard Hinnantba898e42013-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 Clowabadb452015-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 Majnemerf9f95be2014-03-17 20:19:44 +000045class shared_timed_mutex
Howard Hinnantba898e42013-09-21 01:49:28 +000046{
47public:
David Majnemerf9f95be2014-03-17 20:19:44 +000048 shared_timed_mutex();
49 ~shared_timed_mutex();
Howard Hinnantba898e42013-09-21 01:49:28 +000050
David Majnemerf9f95be2014-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 Hinnantba898e42013-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
Eric Fiselier018a3d52017-05-31 22:07:49 +0000128_LIBCPP_PUSH_MACROS
129#include <__undef_macros>
130
131
Louis Dionne6952d142018-08-01 02:08:59 +0000132#if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_LIBRARY)
Howard Hinnantba898e42013-09-21 01:49:28 +0000133
134#include <__mutex_base>
135
Howard Hinnantba898e42013-09-21 01:49:28 +0000136#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
137#pragma GCC system_header
138#endif
139
Jonathan Roelofs8d86b2e2014-09-05 19:45:05 +0000140#ifdef _LIBCPP_HAS_NO_THREADS
141#error <shared_mutex> is not supported on this single threaded system
142#else // !_LIBCPP_HAS_NO_THREADS
143
Howard Hinnantba898e42013-09-21 01:49:28 +0000144_LIBCPP_BEGIN_NAMESPACE_STD
145
Mehdi Amini907c1192017-05-04 17:08:54 +0000146struct _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX __shared_mutex_base
Howard Hinnantba898e42013-09-21 01:49:28 +0000147{
148 mutex __mut_;
149 condition_variable __gate1_;
150 condition_variable __gate2_;
151 unsigned __state_;
152
153 static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
154 static const unsigned __n_readers_ = ~__write_entered_;
Marshall Clowabadb452015-06-30 14:04:14 +0000155
156 __shared_mutex_base();
157 _LIBCPP_INLINE_VISIBILITY ~__shared_mutex_base() = default;
158
159 __shared_mutex_base(const __shared_mutex_base&) = delete;
160 __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
161
162 // Exclusive ownership
163 void lock(); // blocking
164 bool try_lock();
165 void unlock();
166
167 // Shared ownership
168 void lock_shared(); // blocking
169 bool try_lock_shared();
170 void unlock_shared();
171
172// typedef implementation-defined native_handle_type; // See 30.2.3
173// native_handle_type native_handle(); // See 30.2.3
174};
175
176
177#if _LIBCPP_STD_VER > 14
Mehdi Amini907c1192017-05-04 17:08:54 +0000178class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_mutex
Marshall Clowabadb452015-06-30 14:04:14 +0000179{
Marshall Clow59bcc872017-03-24 03:40:36 +0000180 __shared_mutex_base __base;
Marshall Clowabadb452015-06-30 14:04:14 +0000181public:
Eric Fiselier720637d2017-05-08 01:31:50 +0000182 _LIBCPP_INLINE_VISIBILITY shared_mutex() : __base() {}
Marshall Clowabadb452015-06-30 14:04:14 +0000183 _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default;
184
185 shared_mutex(const shared_mutex&) = delete;
186 shared_mutex& operator=(const shared_mutex&) = delete;
187
188 // Exclusive ownership
189 _LIBCPP_INLINE_VISIBILITY void lock() { return __base.lock(); }
190 _LIBCPP_INLINE_VISIBILITY bool try_lock() { return __base.try_lock(); }
191 _LIBCPP_INLINE_VISIBILITY void unlock() { return __base.unlock(); }
192
193 // Shared ownership
194 _LIBCPP_INLINE_VISIBILITY void lock_shared() { return __base.lock_shared(); }
195 _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() { return __base.try_lock_shared(); }
196 _LIBCPP_INLINE_VISIBILITY void unlock_shared() { return __base.unlock_shared(); }
197
198// typedef __shared_mutex_base::native_handle_type native_handle_type;
199// _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() { return __base::unlock_shared(); }
200};
201#endif
202
203
Mehdi Amini907c1192017-05-04 17:08:54 +0000204class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_timed_mutex
Marshall Clowabadb452015-06-30 14:04:14 +0000205{
Marshall Clow59bcc872017-03-24 03:40:36 +0000206 __shared_mutex_base __base;
Howard Hinnantba898e42013-09-21 01:49:28 +0000207public:
David Majnemerf9f95be2014-03-17 20:19:44 +0000208 shared_timed_mutex();
209 _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
Howard Hinnantba898e42013-09-21 01:49:28 +0000210
David Majnemerf9f95be2014-03-17 20:19:44 +0000211 shared_timed_mutex(const shared_timed_mutex&) = delete;
212 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
Howard Hinnantba898e42013-09-21 01:49:28 +0000213
214 // Exclusive ownership
215 void lock();
216 bool try_lock();
217 template <class _Rep, class _Period>
218 _LIBCPP_INLINE_VISIBILITY
219 bool
220 try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
221 {
222 return try_lock_until(chrono::steady_clock::now() + __rel_time);
223 }
224 template <class _Clock, class _Duration>
Shoaib Meenai6b734922017-03-02 03:22:18 +0000225 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
Howard Hinnantba898e42013-09-21 01:49:28 +0000226 bool
227 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
228 void unlock();
229
230 // Shared ownership
231 void lock_shared();
232 bool try_lock_shared();
233 template <class _Rep, class _Period>
234 _LIBCPP_INLINE_VISIBILITY
235 bool
236 try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
237 {
238 return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
239 }
240 template <class _Clock, class _Duration>
Shoaib Meenai6b734922017-03-02 03:22:18 +0000241 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
Howard Hinnantba898e42013-09-21 01:49:28 +0000242 bool
243 try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
244 void unlock_shared();
245};
246
247template <class _Clock, class _Duration>
248bool
David Majnemerf9f95be2014-03-17 20:19:44 +0000249shared_timed_mutex::try_lock_until(
Howard Hinnantba898e42013-09-21 01:49:28 +0000250 const chrono::time_point<_Clock, _Duration>& __abs_time)
251{
Marshall Clowabadb452015-06-30 14:04:14 +0000252 unique_lock<mutex> __lk(__base.__mut_);
253 if (__base.__state_ & __base.__write_entered_)
Howard Hinnantba898e42013-09-21 01:49:28 +0000254 {
255 while (true)
256 {
Marshall Clowabadb452015-06-30 14:04:14 +0000257 cv_status __status = __base.__gate1_.wait_until(__lk, __abs_time);
258 if ((__base.__state_ & __base.__write_entered_) == 0)
Howard Hinnantba898e42013-09-21 01:49:28 +0000259 break;
260 if (__status == cv_status::timeout)
261 return false;
262 }
263 }
Marshall Clowabadb452015-06-30 14:04:14 +0000264 __base.__state_ |= __base.__write_entered_;
265 if (__base.__state_ & __base.__n_readers_)
Howard Hinnantba898e42013-09-21 01:49:28 +0000266 {
267 while (true)
268 {
Marshall Clowabadb452015-06-30 14:04:14 +0000269 cv_status __status = __base.__gate2_.wait_until(__lk, __abs_time);
270 if ((__base.__state_ & __base.__n_readers_) == 0)
Howard Hinnantba898e42013-09-21 01:49:28 +0000271 break;
272 if (__status == cv_status::timeout)
273 {
Marshall Clowabadb452015-06-30 14:04:14 +0000274 __base.__state_ &= ~__base.__write_entered_;
275 __base.__gate1_.notify_all();
Howard Hinnantba898e42013-09-21 01:49:28 +0000276 return false;
277 }
278 }
279 }
280 return true;
281}
282
283template <class _Clock, class _Duration>
284bool
David Majnemerf9f95be2014-03-17 20:19:44 +0000285shared_timed_mutex::try_lock_shared_until(
Howard Hinnantba898e42013-09-21 01:49:28 +0000286 const chrono::time_point<_Clock, _Duration>& __abs_time)
287{
Marshall Clowabadb452015-06-30 14:04:14 +0000288 unique_lock<mutex> __lk(__base.__mut_);
289 if ((__base.__state_ & __base.__write_entered_) || (__base.__state_ & __base.__n_readers_) == __base.__n_readers_)
Howard Hinnantba898e42013-09-21 01:49:28 +0000290 {
291 while (true)
292 {
Marshall Clowabadb452015-06-30 14:04:14 +0000293 cv_status status = __base.__gate1_.wait_until(__lk, __abs_time);
294 if ((__base.__state_ & __base.__write_entered_) == 0 &&
295 (__base.__state_ & __base.__n_readers_) < __base.__n_readers_)
Howard Hinnantba898e42013-09-21 01:49:28 +0000296 break;
297 if (status == cv_status::timeout)
298 return false;
299 }
300 }
Marshall Clowabadb452015-06-30 14:04:14 +0000301 unsigned __num_readers = (__base.__state_ & __base.__n_readers_) + 1;
302 __base.__state_ &= ~__base.__n_readers_;
303 __base.__state_ |= __num_readers;
Howard Hinnantba898e42013-09-21 01:49:28 +0000304 return true;
305}
306
307template <class _Mutex>
308class shared_lock
309{
310public:
311 typedef _Mutex mutex_type;
312
313private:
314 mutex_type* __m_;
315 bool __owns_;
316
317public:
318 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000319 shared_lock() _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000320 : __m_(nullptr),
321 __owns_(false)
322 {}
323
324 _LIBCPP_INLINE_VISIBILITY
325 explicit shared_lock(mutex_type& __m)
Marshall Clow81652492016-04-13 17:02:23 +0000326 : __m_(_VSTD::addressof(__m)),
Howard Hinnantba898e42013-09-21 01:49:28 +0000327 __owns_(true)
328 {__m_->lock_shared();}
329
330 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000331 shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
Marshall Clow81652492016-04-13 17:02:23 +0000332 : __m_(_VSTD::addressof(__m)),
Howard Hinnantba898e42013-09-21 01:49:28 +0000333 __owns_(false)
334 {}
335
336 _LIBCPP_INLINE_VISIBILITY
337 shared_lock(mutex_type& __m, try_to_lock_t)
Marshall Clow81652492016-04-13 17:02:23 +0000338 : __m_(_VSTD::addressof(__m)),
Howard Hinnantba898e42013-09-21 01:49:28 +0000339 __owns_(__m.try_lock_shared())
340 {}
341
342 _LIBCPP_INLINE_VISIBILITY
343 shared_lock(mutex_type& __m, adopt_lock_t)
Marshall Clow81652492016-04-13 17:02:23 +0000344 : __m_(_VSTD::addressof(__m)),
Howard Hinnantba898e42013-09-21 01:49:28 +0000345 __owns_(true)
346 {}
347
348 template <class _Clock, class _Duration>
349 _LIBCPP_INLINE_VISIBILITY
350 shared_lock(mutex_type& __m,
351 const chrono::time_point<_Clock, _Duration>& __abs_time)
Marshall Clow81652492016-04-13 17:02:23 +0000352 : __m_(_VSTD::addressof(__m)),
Howard Hinnantba898e42013-09-21 01:49:28 +0000353 __owns_(__m.try_lock_shared_until(__abs_time))
354 {}
355
356 template <class _Rep, class _Period>
357 _LIBCPP_INLINE_VISIBILITY
358 shared_lock(mutex_type& __m,
359 const chrono::duration<_Rep, _Period>& __rel_time)
Marshall Clow81652492016-04-13 17:02:23 +0000360 : __m_(_VSTD::addressof(__m)),
Howard Hinnantba898e42013-09-21 01:49:28 +0000361 __owns_(__m.try_lock_shared_for(__rel_time))
362 {}
363
364 _LIBCPP_INLINE_VISIBILITY
365 ~shared_lock()
366 {
367 if (__owns_)
368 __m_->unlock_shared();
369 }
370
371 shared_lock(shared_lock const&) = delete;
372 shared_lock& operator=(shared_lock const&) = delete;
373
374 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000375 shared_lock(shared_lock&& __u) _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000376 : __m_(__u.__m_),
377 __owns_(__u.__owns_)
378 {
379 __u.__m_ = nullptr;
380 __u.__owns_ = false;
381 }
382
383 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000384 shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000385 {
386 if (__owns_)
387 __m_->unlock_shared();
388 __m_ = nullptr;
389 __owns_ = false;
390 __m_ = __u.__m_;
391 __owns_ = __u.__owns_;
392 __u.__m_ = nullptr;
393 __u.__owns_ = false;
394 return *this;
395 }
396
397 void lock();
398 bool try_lock();
399 template <class Rep, class Period>
400 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
401 template <class Clock, class Duration>
402 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
403 void unlock();
404
405 // Setters
406 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000407 void swap(shared_lock& __u) _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000408 {
409 _VSTD::swap(__m_, __u.__m_);
410 _VSTD::swap(__owns_, __u.__owns_);
411 }
412
413 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000414 mutex_type* release() _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000415 {
416 mutex_type* __m = __m_;
417 __m_ = nullptr;
418 __owns_ = false;
419 return __m;
420 }
421
422 // Getters
423 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000424 bool owns_lock() const _NOEXCEPT {return __owns_;}
Howard Hinnantba898e42013-09-21 01:49:28 +0000425
426 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000427 explicit operator bool () const _NOEXCEPT {return __owns_;}
Howard Hinnantba898e42013-09-21 01:49:28 +0000428
429 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000430 mutex_type* mutex() const _NOEXCEPT {return __m_;}
Howard Hinnantba898e42013-09-21 01:49:28 +0000431};
432
433template <class _Mutex>
434void
435shared_lock<_Mutex>::lock()
436{
437 if (__m_ == nullptr)
438 __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
439 if (__owns_)
440 __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
441 __m_->lock_shared();
442 __owns_ = true;
443}
444
445template <class _Mutex>
446bool
447shared_lock<_Mutex>::try_lock()
448{
449 if (__m_ == nullptr)
450 __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
451 if (__owns_)
452 __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
453 __owns_ = __m_->try_lock_shared();
454 return __owns_;
455}
456
457template <class _Mutex>
458template <class _Rep, class _Period>
459bool
460shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
461{
462 if (__m_ == nullptr)
463 __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
464 if (__owns_)
465 __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
466 __owns_ = __m_->try_lock_shared_for(__d);
467 return __owns_;
468}
469
470template <class _Mutex>
471template <class _Clock, class _Duration>
472bool
473shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
474{
475 if (__m_ == nullptr)
476 __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
477 if (__owns_)
478 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
479 __owns_ = __m_->try_lock_shared_until(__t);
480 return __owns_;
481}
482
483template <class _Mutex>
484void
485shared_lock<_Mutex>::unlock()
486{
487 if (!__owns_)
488 __throw_system_error(EPERM, "shared_lock::unlock: not locked");
489 __m_->unlock_shared();
490 __owns_ = false;
491}
492
493template <class _Mutex>
494inline _LIBCPP_INLINE_VISIBILITY
495void
Marshall Clow861f1e92014-08-25 14:53:16 +0000496swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000497 {__x.swap(__y);}
498
499_LIBCPP_END_NAMESPACE_STD
500
Jonathan Roelofs8d86b2e2014-09-05 19:45:05 +0000501#endif // !_LIBCPP_HAS_NO_THREADS
502
Howard Hinnantba898e42013-09-21 01:49:28 +0000503#endif // _LIBCPP_STD_VER > 11
504
Eric Fiselier018a3d52017-05-31 22:07:49 +0000505_LIBCPP_POP_MACROS
506
Howard Hinnantba898e42013-09-21 01:49:28 +0000507#endif // _LIBCPP_SHARED_MUTEX