]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/libc++/include/shared_mutex
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / libc++ / include / shared_mutex
1 // -*- 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
19 namespace std
20 {
21
22 class shared_timed_mutex
23 {
24 public:
25     shared_timed_mutex();
26     ~shared_timed_mutex();
27
28     shared_timed_mutex(const shared_timed_mutex&) = delete;
29     shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
30
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
52 template <class Mutex>
53 class shared_lock
54 {
55 public:
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
96 template <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 #ifdef _LIBCPP_HAS_NO_THREADS
116 #error <shared_mutex> is not supported on this single threaded system
117 #else // !_LIBCPP_HAS_NO_THREADS
118
119 _LIBCPP_BEGIN_NAMESPACE_STD
120
121 class _LIBCPP_TYPE_VIS shared_timed_mutex
122 {
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_;
130 public:
131     shared_timed_mutex();
132     _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
133
134     shared_timed_mutex(const shared_timed_mutex&) = delete;
135     shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
136
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
168 template <class _Clock, class _Duration>
169 bool
170 shared_timed_mutex::try_lock_until(
171                         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
203 template <class _Clock, class _Duration>
204 bool
205 shared_timed_mutex::try_lock_shared_until(
206                         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
227 template <class _Mutex>
228 class shared_lock
229 {
230 public:
231     typedef _Mutex mutex_type;
232
233 private:
234     mutex_type* __m_;
235     bool __owns_;
236
237 public:
238     _LIBCPP_INLINE_VISIBILITY
239     shared_lock() _NOEXCEPT
240         : __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
251     shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
252         : __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
295     shared_lock(shared_lock&& __u) _NOEXCEPT
296         : __m_(__u.__m_),
297           __owns_(__u.__owns_)
298         {
299             __u.__m_ = nullptr;
300             __u.__owns_ = false;
301         }
302
303     _LIBCPP_INLINE_VISIBILITY
304     shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
305     {
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
327     void swap(shared_lock& __u) _NOEXCEPT
328     {
329         _VSTD::swap(__m_, __u.__m_);
330         _VSTD::swap(__owns_, __u.__owns_);
331     }
332
333     _LIBCPP_INLINE_VISIBILITY
334     mutex_type* release() _NOEXCEPT
335     {
336         mutex_type* __m = __m_;
337         __m_ = nullptr;
338         __owns_ = false;
339         return __m;
340     }
341
342     // Getters
343     _LIBCPP_INLINE_VISIBILITY
344     bool owns_lock() const _NOEXCEPT {return __owns_;}
345
346     _LIBCPP_INLINE_VISIBILITY
347     explicit operator bool () const _NOEXCEPT {return __owns_;}
348
349     _LIBCPP_INLINE_VISIBILITY
350     mutex_type* mutex() const _NOEXCEPT {return __m_;}
351 };
352
353 template <class _Mutex>
354 void
355 shared_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
365 template <class _Mutex>
366 bool
367 shared_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
377 template <class _Mutex>
378 template <class _Rep, class _Period>
379 bool
380 shared_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
390 template <class _Mutex>
391 template <class _Clock, class _Duration>
392 bool
393 shared_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
403 template <class _Mutex>
404 void
405 shared_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
413 template <class _Mutex>
414 inline _LIBCPP_INLINE_VISIBILITY
415 void
416 swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
417     {__x.swap(__y);}
418
419 _LIBCPP_END_NAMESPACE_STD
420
421 #endif  // !_LIBCPP_HAS_NO_THREADS
422
423 #endif  // _LIBCPP_STD_VER > 11
424
425 #endif  // _LIBCPP_SHARED_MUTEX