blob: 76610548df8281f03458ba6342c7fef94bcd3abe [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
115_LIBCPP_BEGIN_NAMESPACE_STD
116
David Majnemerf9f95be2014-03-17 20:19:44 +0000117class _LIBCPP_TYPE_VIS shared_timed_mutex
Howard Hinnantba898e42013-09-21 01:49:28 +0000118{
119 mutex __mut_;
120 condition_variable __gate1_;
121 condition_variable __gate2_;
122 unsigned __state_;
123
124 static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
125 static const unsigned __n_readers_ = ~__write_entered_;
126public:
David Majnemerf9f95be2014-03-17 20:19:44 +0000127 shared_timed_mutex();
128 _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
Howard Hinnantba898e42013-09-21 01:49:28 +0000129
David Majnemerf9f95be2014-03-17 20:19:44 +0000130 shared_timed_mutex(const shared_timed_mutex&) = delete;
131 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
Howard Hinnantba898e42013-09-21 01:49:28 +0000132
133 // Exclusive ownership
134 void lock();
135 bool try_lock();
136 template <class _Rep, class _Period>
137 _LIBCPP_INLINE_VISIBILITY
138 bool
139 try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
140 {
141 return try_lock_until(chrono::steady_clock::now() + __rel_time);
142 }
143 template <class _Clock, class _Duration>
144 bool
145 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
146 void unlock();
147
148 // Shared ownership
149 void lock_shared();
150 bool try_lock_shared();
151 template <class _Rep, class _Period>
152 _LIBCPP_INLINE_VISIBILITY
153 bool
154 try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
155 {
156 return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
157 }
158 template <class _Clock, class _Duration>
159 bool
160 try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
161 void unlock_shared();
162};
163
164template <class _Clock, class _Duration>
165bool
David Majnemerf9f95be2014-03-17 20:19:44 +0000166shared_timed_mutex::try_lock_until(
Howard Hinnantba898e42013-09-21 01:49:28 +0000167 const chrono::time_point<_Clock, _Duration>& __abs_time)
168{
169 unique_lock<mutex> __lk(__mut_);
170 if (__state_ & __write_entered_)
171 {
172 while (true)
173 {
174 cv_status __status = __gate1_.wait_until(__lk, __abs_time);
175 if ((__state_ & __write_entered_) == 0)
176 break;
177 if (__status == cv_status::timeout)
178 return false;
179 }
180 }
181 __state_ |= __write_entered_;
182 if (__state_ & __n_readers_)
183 {
184 while (true)
185 {
186 cv_status __status = __gate2_.wait_until(__lk, __abs_time);
187 if ((__state_ & __n_readers_) == 0)
188 break;
189 if (__status == cv_status::timeout)
190 {
191 __state_ &= ~__write_entered_;
192 return false;
193 }
194 }
195 }
196 return true;
197}
198
199template <class _Clock, class _Duration>
200bool
David Majnemerf9f95be2014-03-17 20:19:44 +0000201shared_timed_mutex::try_lock_shared_until(
Howard Hinnantba898e42013-09-21 01:49:28 +0000202 const chrono::time_point<_Clock, _Duration>& __abs_time)
203{
204 unique_lock<mutex> __lk(__mut_);
205 if ((__state_ & __write_entered_) || (__state_ & __n_readers_) == __n_readers_)
206 {
207 while (true)
208 {
209 cv_status status = __gate1_.wait_until(__lk, __abs_time);
210 if ((__state_ & __write_entered_) == 0 &&
211 (__state_ & __n_readers_) < __n_readers_)
212 break;
213 if (status == cv_status::timeout)
214 return false;
215 }
216 }
217 unsigned __num_readers = (__state_ & __n_readers_) + 1;
218 __state_ &= ~__n_readers_;
219 __state_ |= __num_readers;
220 return true;
221}
222
223template <class _Mutex>
224class shared_lock
225{
226public:
227 typedef _Mutex mutex_type;
228
229private:
230 mutex_type* __m_;
231 bool __owns_;
232
233public:
234 _LIBCPP_INLINE_VISIBILITY
235 shared_lock() noexcept
236 : __m_(nullptr),
237 __owns_(false)
238 {}
239
240 _LIBCPP_INLINE_VISIBILITY
241 explicit shared_lock(mutex_type& __m)
242 : __m_(&__m),
243 __owns_(true)
244 {__m_->lock_shared();}
245
246 _LIBCPP_INLINE_VISIBILITY
247 shared_lock(mutex_type& __m, defer_lock_t) noexcept
248 : __m_(&__m),
249 __owns_(false)
250 {}
251
252 _LIBCPP_INLINE_VISIBILITY
253 shared_lock(mutex_type& __m, try_to_lock_t)
254 : __m_(&__m),
255 __owns_(__m.try_lock_shared())
256 {}
257
258 _LIBCPP_INLINE_VISIBILITY
259 shared_lock(mutex_type& __m, adopt_lock_t)
260 : __m_(&__m),
261 __owns_(true)
262 {}
263
264 template <class _Clock, class _Duration>
265 _LIBCPP_INLINE_VISIBILITY
266 shared_lock(mutex_type& __m,
267 const chrono::time_point<_Clock, _Duration>& __abs_time)
268 : __m_(&__m),
269 __owns_(__m.try_lock_shared_until(__abs_time))
270 {}
271
272 template <class _Rep, class _Period>
273 _LIBCPP_INLINE_VISIBILITY
274 shared_lock(mutex_type& __m,
275 const chrono::duration<_Rep, _Period>& __rel_time)
276 : __m_(&__m),
277 __owns_(__m.try_lock_shared_for(__rel_time))
278 {}
279
280 _LIBCPP_INLINE_VISIBILITY
281 ~shared_lock()
282 {
283 if (__owns_)
284 __m_->unlock_shared();
285 }
286
287 shared_lock(shared_lock const&) = delete;
288 shared_lock& operator=(shared_lock const&) = delete;
289
290 _LIBCPP_INLINE_VISIBILITY
291 shared_lock(shared_lock&& __u) noexcept
292 : __m_(__u.__m_),
293 __owns_(__u.__owns_)
294 {
295 __u.__m_ = nullptr;
296 __u.__owns_ = false;
297 }
298
299 _LIBCPP_INLINE_VISIBILITY
300 shared_lock& operator=(shared_lock&& __u) noexcept
301 {
302 if (__owns_)
303 __m_->unlock_shared();
304 __m_ = nullptr;
305 __owns_ = false;
306 __m_ = __u.__m_;
307 __owns_ = __u.__owns_;
308 __u.__m_ = nullptr;
309 __u.__owns_ = false;
310 return *this;
311 }
312
313 void lock();
314 bool try_lock();
315 template <class Rep, class Period>
316 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
317 template <class Clock, class Duration>
318 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
319 void unlock();
320
321 // Setters
322 _LIBCPP_INLINE_VISIBILITY
323 void swap(shared_lock& __u) noexcept
324 {
325 _VSTD::swap(__m_, __u.__m_);
326 _VSTD::swap(__owns_, __u.__owns_);
327 }
328
329 _LIBCPP_INLINE_VISIBILITY
330 mutex_type* release() noexcept
331 {
332 mutex_type* __m = __m_;
333 __m_ = nullptr;
334 __owns_ = false;
335 return __m;
336 }
337
338 // Getters
339 _LIBCPP_INLINE_VISIBILITY
340 bool owns_lock() const noexcept {return __owns_;}
341
342 _LIBCPP_INLINE_VISIBILITY
343 explicit operator bool () const noexcept {return __owns_;}
344
345 _LIBCPP_INLINE_VISIBILITY
346 mutex_type* mutex() const noexcept {return __m_;}
347};
348
349template <class _Mutex>
350void
351shared_lock<_Mutex>::lock()
352{
353 if (__m_ == nullptr)
354 __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
355 if (__owns_)
356 __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
357 __m_->lock_shared();
358 __owns_ = true;
359}
360
361template <class _Mutex>
362bool
363shared_lock<_Mutex>::try_lock()
364{
365 if (__m_ == nullptr)
366 __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
367 if (__owns_)
368 __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
369 __owns_ = __m_->try_lock_shared();
370 return __owns_;
371}
372
373template <class _Mutex>
374template <class _Rep, class _Period>
375bool
376shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
377{
378 if (__m_ == nullptr)
379 __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
380 if (__owns_)
381 __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
382 __owns_ = __m_->try_lock_shared_for(__d);
383 return __owns_;
384}
385
386template <class _Mutex>
387template <class _Clock, class _Duration>
388bool
389shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
390{
391 if (__m_ == nullptr)
392 __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
393 if (__owns_)
394 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
395 __owns_ = __m_->try_lock_shared_until(__t);
396 return __owns_;
397}
398
399template <class _Mutex>
400void
401shared_lock<_Mutex>::unlock()
402{
403 if (!__owns_)
404 __throw_system_error(EPERM, "shared_lock::unlock: not locked");
405 __m_->unlock_shared();
406 __owns_ = false;
407}
408
409template <class _Mutex>
410inline _LIBCPP_INLINE_VISIBILITY
411void
412swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) noexcept
413 {__x.swap(__y);}
414
415_LIBCPP_END_NAMESPACE_STD
416
417#endif // _LIBCPP_STD_VER > 11
418
419#endif // _LIBCPP_SHARED_MUTEX