blob: c97b147efceb060041563fb92e4f091c0efeb908 [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
David Majnemerf9f95be2014-03-17 20:19:44 +000022class shared_timed_mutex
Howard Hinnantba898e42013-09-21 01:49:28 +000023{
24public:
David Majnemerf9f95be2014-03-17 20:19:44 +000025 shared_timed_mutex();
26 ~shared_timed_mutex();
Howard Hinnantba898e42013-09-21 01:49:28 +000027
David Majnemerf9f95be2014-03-17 20:19:44 +000028 shared_timed_mutex(const shared_timed_mutex&) = delete;
29 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
Howard Hinnantba898e42013-09-21 01:49:28 +000030
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
52template <class Mutex>
53class shared_lock
54{
55public:
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
96template <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
Jonathan Roelofs8d86b2e2014-09-05 19:45:05 +0000115#ifdef _LIBCPP_HAS_NO_THREADS
116#error <shared_mutex> is not supported on this single threaded system
117#else // !_LIBCPP_HAS_NO_THREADS
118
Howard Hinnantba898e42013-09-21 01:49:28 +0000119_LIBCPP_BEGIN_NAMESPACE_STD
120
David Majnemerf9f95be2014-03-17 20:19:44 +0000121class _LIBCPP_TYPE_VIS shared_timed_mutex
Howard Hinnantba898e42013-09-21 01:49:28 +0000122{
123 mutex __mut_;
124 condition_variable __gate1_;
125 condition_variable __gate2_;
126 unsigned __state_;
127
128 static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
129 static const unsigned __n_readers_ = ~__write_entered_;
130public:
David Majnemerf9f95be2014-03-17 20:19:44 +0000131 shared_timed_mutex();
132 _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
Howard Hinnantba898e42013-09-21 01:49:28 +0000133
David Majnemerf9f95be2014-03-17 20:19:44 +0000134 shared_timed_mutex(const shared_timed_mutex&) = delete;
135 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
Howard Hinnantba898e42013-09-21 01:49:28 +0000136
137 // Exclusive ownership
138 void lock();
139 bool try_lock();
140 template <class _Rep, class _Period>
141 _LIBCPP_INLINE_VISIBILITY
142 bool
143 try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
144 {
145 return try_lock_until(chrono::steady_clock::now() + __rel_time);
146 }
147 template <class _Clock, class _Duration>
148 bool
149 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
150 void unlock();
151
152 // Shared ownership
153 void lock_shared();
154 bool try_lock_shared();
155 template <class _Rep, class _Period>
156 _LIBCPP_INLINE_VISIBILITY
157 bool
158 try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
159 {
160 return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
161 }
162 template <class _Clock, class _Duration>
163 bool
164 try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
165 void unlock_shared();
166};
167
168template <class _Clock, class _Duration>
169bool
David Majnemerf9f95be2014-03-17 20:19:44 +0000170shared_timed_mutex::try_lock_until(
Howard Hinnantba898e42013-09-21 01:49:28 +0000171 const chrono::time_point<_Clock, _Duration>& __abs_time)
172{
173 unique_lock<mutex> __lk(__mut_);
174 if (__state_ & __write_entered_)
175 {
176 while (true)
177 {
178 cv_status __status = __gate1_.wait_until(__lk, __abs_time);
179 if ((__state_ & __write_entered_) == 0)
180 break;
181 if (__status == cv_status::timeout)
182 return false;
183 }
184 }
185 __state_ |= __write_entered_;
186 if (__state_ & __n_readers_)
187 {
188 while (true)
189 {
190 cv_status __status = __gate2_.wait_until(__lk, __abs_time);
191 if ((__state_ & __n_readers_) == 0)
192 break;
193 if (__status == cv_status::timeout)
194 {
195 __state_ &= ~__write_entered_;
Eric Fiselier1d55ecf2015-04-02 21:02:06 +0000196 __gate1_.notify_all();
Howard Hinnantba898e42013-09-21 01:49:28 +0000197 return false;
198 }
199 }
200 }
201 return true;
202}
203
204template <class _Clock, class _Duration>
205bool
David Majnemerf9f95be2014-03-17 20:19:44 +0000206shared_timed_mutex::try_lock_shared_until(
Howard Hinnantba898e42013-09-21 01:49:28 +0000207 const chrono::time_point<_Clock, _Duration>& __abs_time)
208{
209 unique_lock<mutex> __lk(__mut_);
210 if ((__state_ & __write_entered_) || (__state_ & __n_readers_) == __n_readers_)
211 {
212 while (true)
213 {
214 cv_status status = __gate1_.wait_until(__lk, __abs_time);
215 if ((__state_ & __write_entered_) == 0 &&
216 (__state_ & __n_readers_) < __n_readers_)
217 break;
218 if (status == cv_status::timeout)
219 return false;
220 }
221 }
222 unsigned __num_readers = (__state_ & __n_readers_) + 1;
223 __state_ &= ~__n_readers_;
224 __state_ |= __num_readers;
225 return true;
226}
227
228template <class _Mutex>
229class shared_lock
230{
231public:
232 typedef _Mutex mutex_type;
233
234private:
235 mutex_type* __m_;
236 bool __owns_;
237
238public:
239 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000240 shared_lock() _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000241 : __m_(nullptr),
242 __owns_(false)
243 {}
244
245 _LIBCPP_INLINE_VISIBILITY
246 explicit shared_lock(mutex_type& __m)
247 : __m_(&__m),
248 __owns_(true)
249 {__m_->lock_shared();}
250
251 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000252 shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000253 : __m_(&__m),
254 __owns_(false)
255 {}
256
257 _LIBCPP_INLINE_VISIBILITY
258 shared_lock(mutex_type& __m, try_to_lock_t)
259 : __m_(&__m),
260 __owns_(__m.try_lock_shared())
261 {}
262
263 _LIBCPP_INLINE_VISIBILITY
264 shared_lock(mutex_type& __m, adopt_lock_t)
265 : __m_(&__m),
266 __owns_(true)
267 {}
268
269 template <class _Clock, class _Duration>
270 _LIBCPP_INLINE_VISIBILITY
271 shared_lock(mutex_type& __m,
272 const chrono::time_point<_Clock, _Duration>& __abs_time)
273 : __m_(&__m),
274 __owns_(__m.try_lock_shared_until(__abs_time))
275 {}
276
277 template <class _Rep, class _Period>
278 _LIBCPP_INLINE_VISIBILITY
279 shared_lock(mutex_type& __m,
280 const chrono::duration<_Rep, _Period>& __rel_time)
281 : __m_(&__m),
282 __owns_(__m.try_lock_shared_for(__rel_time))
283 {}
284
285 _LIBCPP_INLINE_VISIBILITY
286 ~shared_lock()
287 {
288 if (__owns_)
289 __m_->unlock_shared();
290 }
291
292 shared_lock(shared_lock const&) = delete;
293 shared_lock& operator=(shared_lock const&) = delete;
294
295 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000296 shared_lock(shared_lock&& __u) _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000297 : __m_(__u.__m_),
298 __owns_(__u.__owns_)
299 {
300 __u.__m_ = nullptr;
301 __u.__owns_ = false;
302 }
303
304 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000305 shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000306 {
307 if (__owns_)
308 __m_->unlock_shared();
309 __m_ = nullptr;
310 __owns_ = false;
311 __m_ = __u.__m_;
312 __owns_ = __u.__owns_;
313 __u.__m_ = nullptr;
314 __u.__owns_ = false;
315 return *this;
316 }
317
318 void lock();
319 bool try_lock();
320 template <class Rep, class Period>
321 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
322 template <class Clock, class Duration>
323 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
324 void unlock();
325
326 // Setters
327 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000328 void swap(shared_lock& __u) _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000329 {
330 _VSTD::swap(__m_, __u.__m_);
331 _VSTD::swap(__owns_, __u.__owns_);
332 }
333
334 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000335 mutex_type* release() _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000336 {
337 mutex_type* __m = __m_;
338 __m_ = nullptr;
339 __owns_ = false;
340 return __m;
341 }
342
343 // Getters
344 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000345 bool owns_lock() const _NOEXCEPT {return __owns_;}
Howard Hinnantba898e42013-09-21 01:49:28 +0000346
347 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000348 explicit operator bool () const _NOEXCEPT {return __owns_;}
Howard Hinnantba898e42013-09-21 01:49:28 +0000349
350 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000351 mutex_type* mutex() const _NOEXCEPT {return __m_;}
Howard Hinnantba898e42013-09-21 01:49:28 +0000352};
353
354template <class _Mutex>
355void
356shared_lock<_Mutex>::lock()
357{
358 if (__m_ == nullptr)
359 __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
360 if (__owns_)
361 __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
362 __m_->lock_shared();
363 __owns_ = true;
364}
365
366template <class _Mutex>
367bool
368shared_lock<_Mutex>::try_lock()
369{
370 if (__m_ == nullptr)
371 __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
372 if (__owns_)
373 __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
374 __owns_ = __m_->try_lock_shared();
375 return __owns_;
376}
377
378template <class _Mutex>
379template <class _Rep, class _Period>
380bool
381shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
382{
383 if (__m_ == nullptr)
384 __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
385 if (__owns_)
386 __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
387 __owns_ = __m_->try_lock_shared_for(__d);
388 return __owns_;
389}
390
391template <class _Mutex>
392template <class _Clock, class _Duration>
393bool
394shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
395{
396 if (__m_ == nullptr)
397 __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
398 if (__owns_)
399 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
400 __owns_ = __m_->try_lock_shared_until(__t);
401 return __owns_;
402}
403
404template <class _Mutex>
405void
406shared_lock<_Mutex>::unlock()
407{
408 if (!__owns_)
409 __throw_system_error(EPERM, "shared_lock::unlock: not locked");
410 __m_->unlock_shared();
411 __owns_ = false;
412}
413
414template <class _Mutex>
415inline _LIBCPP_INLINE_VISIBILITY
416void
Marshall Clow861f1e92014-08-25 14:53:16 +0000417swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000418 {__x.swap(__y);}
419
420_LIBCPP_END_NAMESPACE_STD
421
Jonathan Roelofs8d86b2e2014-09-05 19:45:05 +0000422#endif // !_LIBCPP_HAS_NO_THREADS
423
Howard Hinnantba898e42013-09-21 01:49:28 +0000424#endif // _LIBCPP_STD_VER > 11
425
426#endif // _LIBCPP_SHARED_MUTEX