blob: 9b7f0bf7735464f266e3ac035a2a709571eb1469 [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_;
196 return false;
197 }
198 }
199 }
200 return true;
201}
202
203template <class _Clock, class _Duration>
204bool
David Majnemerf9f95be2014-03-17 20:19:44 +0000205shared_timed_mutex::try_lock_shared_until(
Howard Hinnantba898e42013-09-21 01:49:28 +0000206 const chrono::time_point<_Clock, _Duration>& __abs_time)
207{
208 unique_lock<mutex> __lk(__mut_);
209 if ((__state_ & __write_entered_) || (__state_ & __n_readers_) == __n_readers_)
210 {
211 while (true)
212 {
213 cv_status status = __gate1_.wait_until(__lk, __abs_time);
214 if ((__state_ & __write_entered_) == 0 &&
215 (__state_ & __n_readers_) < __n_readers_)
216 break;
217 if (status == cv_status::timeout)
218 return false;
219 }
220 }
221 unsigned __num_readers = (__state_ & __n_readers_) + 1;
222 __state_ &= ~__n_readers_;
223 __state_ |= __num_readers;
224 return true;
225}
226
227template <class _Mutex>
228class shared_lock
229{
230public:
231 typedef _Mutex mutex_type;
232
233private:
234 mutex_type* __m_;
235 bool __owns_;
236
237public:
238 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000239 shared_lock() _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000240 : __m_(nullptr),
241 __owns_(false)
242 {}
243
244 _LIBCPP_INLINE_VISIBILITY
245 explicit shared_lock(mutex_type& __m)
246 : __m_(&__m),
247 __owns_(true)
248 {__m_->lock_shared();}
249
250 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000251 shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000252 : __m_(&__m),
253 __owns_(false)
254 {}
255
256 _LIBCPP_INLINE_VISIBILITY
257 shared_lock(mutex_type& __m, try_to_lock_t)
258 : __m_(&__m),
259 __owns_(__m.try_lock_shared())
260 {}
261
262 _LIBCPP_INLINE_VISIBILITY
263 shared_lock(mutex_type& __m, adopt_lock_t)
264 : __m_(&__m),
265 __owns_(true)
266 {}
267
268 template <class _Clock, class _Duration>
269 _LIBCPP_INLINE_VISIBILITY
270 shared_lock(mutex_type& __m,
271 const chrono::time_point<_Clock, _Duration>& __abs_time)
272 : __m_(&__m),
273 __owns_(__m.try_lock_shared_until(__abs_time))
274 {}
275
276 template <class _Rep, class _Period>
277 _LIBCPP_INLINE_VISIBILITY
278 shared_lock(mutex_type& __m,
279 const chrono::duration<_Rep, _Period>& __rel_time)
280 : __m_(&__m),
281 __owns_(__m.try_lock_shared_for(__rel_time))
282 {}
283
284 _LIBCPP_INLINE_VISIBILITY
285 ~shared_lock()
286 {
287 if (__owns_)
288 __m_->unlock_shared();
289 }
290
291 shared_lock(shared_lock const&) = delete;
292 shared_lock& operator=(shared_lock const&) = delete;
293
294 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000295 shared_lock(shared_lock&& __u) _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000296 : __m_(__u.__m_),
297 __owns_(__u.__owns_)
298 {
299 __u.__m_ = nullptr;
300 __u.__owns_ = false;
301 }
302
303 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000304 shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000305 {
306 if (__owns_)
307 __m_->unlock_shared();
308 __m_ = nullptr;
309 __owns_ = false;
310 __m_ = __u.__m_;
311 __owns_ = __u.__owns_;
312 __u.__m_ = nullptr;
313 __u.__owns_ = false;
314 return *this;
315 }
316
317 void lock();
318 bool try_lock();
319 template <class Rep, class Period>
320 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
321 template <class Clock, class Duration>
322 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
323 void unlock();
324
325 // Setters
326 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000327 void swap(shared_lock& __u) _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000328 {
329 _VSTD::swap(__m_, __u.__m_);
330 _VSTD::swap(__owns_, __u.__owns_);
331 }
332
333 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000334 mutex_type* release() _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000335 {
336 mutex_type* __m = __m_;
337 __m_ = nullptr;
338 __owns_ = false;
339 return __m;
340 }
341
342 // Getters
343 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000344 bool owns_lock() const _NOEXCEPT {return __owns_;}
Howard Hinnantba898e42013-09-21 01:49:28 +0000345
346 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000347 explicit operator bool () const _NOEXCEPT {return __owns_;}
Howard Hinnantba898e42013-09-21 01:49:28 +0000348
349 _LIBCPP_INLINE_VISIBILITY
Marshall Clow861f1e92014-08-25 14:53:16 +0000350 mutex_type* mutex() const _NOEXCEPT {return __m_;}
Howard Hinnantba898e42013-09-21 01:49:28 +0000351};
352
353template <class _Mutex>
354void
355shared_lock<_Mutex>::lock()
356{
357 if (__m_ == nullptr)
358 __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
359 if (__owns_)
360 __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
361 __m_->lock_shared();
362 __owns_ = true;
363}
364
365template <class _Mutex>
366bool
367shared_lock<_Mutex>::try_lock()
368{
369 if (__m_ == nullptr)
370 __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
371 if (__owns_)
372 __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
373 __owns_ = __m_->try_lock_shared();
374 return __owns_;
375}
376
377template <class _Mutex>
378template <class _Rep, class _Period>
379bool
380shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
381{
382 if (__m_ == nullptr)
383 __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
384 if (__owns_)
385 __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
386 __owns_ = __m_->try_lock_shared_for(__d);
387 return __owns_;
388}
389
390template <class _Mutex>
391template <class _Clock, class _Duration>
392bool
393shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
394{
395 if (__m_ == nullptr)
396 __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
397 if (__owns_)
398 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
399 __owns_ = __m_->try_lock_shared_until(__t);
400 return __owns_;
401}
402
403template <class _Mutex>
404void
405shared_lock<_Mutex>::unlock()
406{
407 if (!__owns_)
408 __throw_system_error(EPERM, "shared_lock::unlock: not locked");
409 __m_->unlock_shared();
410 __owns_ = false;
411}
412
413template <class _Mutex>
414inline _LIBCPP_INLINE_VISIBILITY
415void
Marshall Clow861f1e92014-08-25 14:53:16 +0000416swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
Howard Hinnantba898e42013-09-21 01:49:28 +0000417 {__x.swap(__y);}
418
419_LIBCPP_END_NAMESPACE_STD
420
Jonathan Roelofs8d86b2e2014-09-05 19:45:05 +0000421#endif // !_LIBCPP_HAS_NO_THREADS
422
Howard Hinnantba898e42013-09-21 01:49:28 +0000423#endif // _LIBCPP_STD_VER > 11
424
425#endif // _LIBCPP_SHARED_MUTEX