]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libc++/include/shared_mutex
Merge libc++ trunk r300890, and update build glue.
[FreeBSD/FreeBSD.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_mutex      // C++17
23 {
24 public:
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
45 class shared_timed_mutex
46 {
47 public:
48     shared_timed_mutex();
49     ~shared_timed_mutex();
50
51     shared_timed_mutex(const shared_timed_mutex&) = delete;
52     shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
53
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
75 template <class Mutex>
76 class shared_lock
77 {
78 public:
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
119 template <class Mutex>
120     void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
121
122 }  // std
123
124 */
125
126 #include <__config>
127
128 #if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_SHARED_MUTEX)
129
130 #include <__mutex_base>
131
132 #include <__undef_min_max>
133
134 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
135 #pragma GCC system_header
136 #endif
137
138 #ifdef _LIBCPP_HAS_NO_THREADS
139 #error <shared_mutex> is not supported on this single threaded system
140 #else // !_LIBCPP_HAS_NO_THREADS
141
142 _LIBCPP_BEGIN_NAMESPACE_STD
143
144 struct _LIBCPP_TYPE_VIS __shared_mutex_base
145 {
146     mutex               __mut_;
147     condition_variable  __gate1_;
148     condition_variable  __gate2_;
149     unsigned            __state_;
150
151     static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
152     static const unsigned __n_readers_ = ~__write_entered_;
153
154     __shared_mutex_base();
155     _LIBCPP_INLINE_VISIBILITY ~__shared_mutex_base() = default;
156
157     __shared_mutex_base(const __shared_mutex_base&) = delete;
158     __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
159
160     // Exclusive ownership
161     void lock(); // blocking
162     bool try_lock();
163     void unlock();
164
165     // Shared ownership
166     void lock_shared(); // blocking
167     bool try_lock_shared();
168     void unlock_shared();
169
170 //     typedef implementation-defined native_handle_type; // See 30.2.3
171 //     native_handle_type native_handle(); // See 30.2.3
172 };
173
174
175 #if _LIBCPP_STD_VER > 14
176 class _LIBCPP_TYPE_VIS shared_mutex
177 {
178     __shared_mutex_base __base;
179 public:
180     shared_mutex() : __base() {}
181     _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default;
182
183     shared_mutex(const shared_mutex&) = delete;
184     shared_mutex& operator=(const shared_mutex&) = delete;
185
186     // Exclusive ownership
187     _LIBCPP_INLINE_VISIBILITY void lock()     { return __base.lock(); }
188     _LIBCPP_INLINE_VISIBILITY bool try_lock() { return __base.try_lock(); }
189     _LIBCPP_INLINE_VISIBILITY void unlock()   { return __base.unlock(); }
190
191     // Shared ownership
192     _LIBCPP_INLINE_VISIBILITY void lock_shared()     { return __base.lock_shared(); }
193     _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() { return __base.try_lock_shared(); }
194     _LIBCPP_INLINE_VISIBILITY void unlock_shared()   { return __base.unlock_shared(); }
195
196 //     typedef __shared_mutex_base::native_handle_type native_handle_type;
197 //     _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() { return __base::unlock_shared(); }
198 };
199 #endif
200
201
202 class _LIBCPP_TYPE_VIS shared_timed_mutex
203 {
204     __shared_mutex_base __base;
205 public:
206     shared_timed_mutex();
207     _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
208
209     shared_timed_mutex(const shared_timed_mutex&) = delete;
210     shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
211
212     // Exclusive ownership
213     void lock();
214     bool try_lock();
215     template <class _Rep, class _Period>
216         _LIBCPP_INLINE_VISIBILITY
217         bool
218         try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
219         {
220             return try_lock_until(chrono::steady_clock::now() + __rel_time);
221         }
222     template <class _Clock, class _Duration>
223         _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
224         bool
225         try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
226     void unlock();
227
228     // Shared ownership
229     void lock_shared();
230     bool try_lock_shared();
231     template <class _Rep, class _Period>
232         _LIBCPP_INLINE_VISIBILITY
233         bool
234         try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
235         {
236             return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
237         }
238     template <class _Clock, class _Duration>
239         _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
240         bool
241         try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
242     void unlock_shared();
243 };
244
245 template <class _Clock, class _Duration>
246 bool
247 shared_timed_mutex::try_lock_until(
248                         const chrono::time_point<_Clock, _Duration>& __abs_time)
249 {
250     unique_lock<mutex> __lk(__base.__mut_);
251     if (__base.__state_ & __base.__write_entered_)
252     {
253         while (true)
254         {
255             cv_status __status = __base.__gate1_.wait_until(__lk, __abs_time);
256             if ((__base.__state_ & __base.__write_entered_) == 0)
257                 break;
258             if (__status == cv_status::timeout)
259                 return false;
260         }
261     }
262     __base.__state_ |= __base.__write_entered_;
263     if (__base.__state_ & __base.__n_readers_)
264     {
265         while (true)
266         {
267             cv_status __status = __base.__gate2_.wait_until(__lk, __abs_time);
268             if ((__base.__state_ & __base.__n_readers_) == 0)
269                 break;
270             if (__status == cv_status::timeout)
271             {
272                 __base.__state_ &= ~__base.__write_entered_;
273                 __base.__gate1_.notify_all();
274                 return false;
275             }
276         }
277     }
278     return true;
279 }
280
281 template <class _Clock, class _Duration>
282 bool
283 shared_timed_mutex::try_lock_shared_until(
284                         const chrono::time_point<_Clock, _Duration>& __abs_time)
285 {
286     unique_lock<mutex> __lk(__base.__mut_);
287     if ((__base.__state_ & __base.__write_entered_) || (__base.__state_ & __base.__n_readers_) == __base.__n_readers_)
288     {
289         while (true)
290         {
291             cv_status status = __base.__gate1_.wait_until(__lk, __abs_time);
292             if ((__base.__state_ & __base.__write_entered_) == 0 &&
293                                        (__base.__state_ & __base.__n_readers_) < __base.__n_readers_)
294                 break;
295             if (status == cv_status::timeout)
296                 return false;
297         }
298     }
299     unsigned __num_readers = (__base.__state_ & __base.__n_readers_) + 1;
300     __base.__state_ &= ~__base.__n_readers_;
301     __base.__state_ |= __num_readers;
302     return true;
303 }
304
305 template <class _Mutex>
306 class shared_lock
307 {
308 public:
309     typedef _Mutex mutex_type;
310
311 private:
312     mutex_type* __m_;
313     bool __owns_;
314
315 public:
316     _LIBCPP_INLINE_VISIBILITY
317     shared_lock() _NOEXCEPT
318         : __m_(nullptr),
319           __owns_(false)
320         {}
321
322     _LIBCPP_INLINE_VISIBILITY
323     explicit shared_lock(mutex_type& __m)
324         : __m_(_VSTD::addressof(__m)),
325           __owns_(true)
326         {__m_->lock_shared();}
327
328     _LIBCPP_INLINE_VISIBILITY
329     shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
330         : __m_(_VSTD::addressof(__m)),
331           __owns_(false)
332         {}
333
334     _LIBCPP_INLINE_VISIBILITY
335     shared_lock(mutex_type& __m, try_to_lock_t)
336         : __m_(_VSTD::addressof(__m)),
337           __owns_(__m.try_lock_shared())
338         {}
339
340     _LIBCPP_INLINE_VISIBILITY
341     shared_lock(mutex_type& __m, adopt_lock_t)
342         : __m_(_VSTD::addressof(__m)),
343           __owns_(true)
344         {}
345
346     template <class _Clock, class _Duration>
347         _LIBCPP_INLINE_VISIBILITY
348         shared_lock(mutex_type& __m,
349                     const chrono::time_point<_Clock, _Duration>& __abs_time)
350             : __m_(_VSTD::addressof(__m)),
351               __owns_(__m.try_lock_shared_until(__abs_time))
352             {}
353
354     template <class _Rep, class _Period>
355         _LIBCPP_INLINE_VISIBILITY
356         shared_lock(mutex_type& __m,
357                     const chrono::duration<_Rep, _Period>& __rel_time)
358             : __m_(_VSTD::addressof(__m)),
359               __owns_(__m.try_lock_shared_for(__rel_time))
360             {}
361
362     _LIBCPP_INLINE_VISIBILITY
363     ~shared_lock()
364     {
365         if (__owns_)
366             __m_->unlock_shared();
367     }
368
369     shared_lock(shared_lock const&) = delete;
370     shared_lock& operator=(shared_lock const&) = delete;
371
372     _LIBCPP_INLINE_VISIBILITY
373     shared_lock(shared_lock&& __u) _NOEXCEPT
374         : __m_(__u.__m_),
375           __owns_(__u.__owns_)
376         {
377             __u.__m_ = nullptr;
378             __u.__owns_ = false;
379         }
380
381     _LIBCPP_INLINE_VISIBILITY
382     shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
383     {
384         if (__owns_)
385             __m_->unlock_shared();
386         __m_ = nullptr;
387         __owns_ = false;
388         __m_ = __u.__m_;
389         __owns_ = __u.__owns_;
390         __u.__m_ = nullptr;
391         __u.__owns_ = false;
392         return *this;
393     }
394
395     void lock();
396     bool try_lock();
397     template <class Rep, class Period>
398         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
399     template <class Clock, class Duration>
400         bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
401     void unlock();
402
403     // Setters
404     _LIBCPP_INLINE_VISIBILITY
405     void swap(shared_lock& __u) _NOEXCEPT
406     {
407         _VSTD::swap(__m_, __u.__m_);
408         _VSTD::swap(__owns_, __u.__owns_);
409     }
410
411     _LIBCPP_INLINE_VISIBILITY
412     mutex_type* release() _NOEXCEPT
413     {
414         mutex_type* __m = __m_;
415         __m_ = nullptr;
416         __owns_ = false;
417         return __m;
418     }
419
420     // Getters
421     _LIBCPP_INLINE_VISIBILITY
422     bool owns_lock() const _NOEXCEPT {return __owns_;}
423
424     _LIBCPP_INLINE_VISIBILITY
425     explicit operator bool () const _NOEXCEPT {return __owns_;}
426
427     _LIBCPP_INLINE_VISIBILITY
428     mutex_type* mutex() const _NOEXCEPT {return __m_;}
429 };
430
431 template <class _Mutex>
432 void
433 shared_lock<_Mutex>::lock()
434 {
435     if (__m_ == nullptr)
436         __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
437     if (__owns_)
438         __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
439     __m_->lock_shared();
440     __owns_ = true;
441 }
442
443 template <class _Mutex>
444 bool
445 shared_lock<_Mutex>::try_lock()
446 {
447     if (__m_ == nullptr)
448         __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
449     if (__owns_)
450         __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
451     __owns_ = __m_->try_lock_shared();
452     return __owns_;
453 }
454
455 template <class _Mutex>
456 template <class _Rep, class _Period>
457 bool
458 shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
459 {
460     if (__m_ == nullptr)
461         __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
462     if (__owns_)
463         __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
464     __owns_ = __m_->try_lock_shared_for(__d);
465     return __owns_;
466 }
467
468 template <class _Mutex>
469 template <class _Clock, class _Duration>
470 bool
471 shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
472 {
473     if (__m_ == nullptr)
474         __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
475     if (__owns_)
476         __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
477     __owns_ = __m_->try_lock_shared_until(__t);
478     return __owns_;
479 }
480
481 template <class _Mutex>
482 void
483 shared_lock<_Mutex>::unlock()
484 {
485     if (!__owns_)
486         __throw_system_error(EPERM, "shared_lock::unlock: not locked");
487     __m_->unlock_shared();
488     __owns_ = false;
489 }
490
491 template <class _Mutex>
492 inline _LIBCPP_INLINE_VISIBILITY
493 void
494 swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
495     {__x.swap(__y);}
496
497 _LIBCPP_END_NAMESPACE_STD
498
499 #endif  // !_LIBCPP_HAS_NO_THREADS
500
501 #endif  // _LIBCPP_STD_VER > 11
502
503 #endif  // _LIBCPP_SHARED_MUTEX