]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/libcxx/include/shared_mutex
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm-project / libcxx / include / shared_mutex
1 // -*- C++ -*-
2 //===------------------------ shared_mutex --------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9
10 #ifndef _LIBCPP_SHARED_MUTEX
11 #define _LIBCPP_SHARED_MUTEX
12
13 /*
14     shared_mutex synopsis
15
16 // C++1y
17
18 namespace std
19 {
20
21 class shared_mutex      // C++17
22 {
23 public:
24     shared_mutex();
25     ~shared_mutex();
26
27     shared_mutex(const shared_mutex&) = delete;
28     shared_mutex& operator=(const shared_mutex&) = delete;
29
30     // Exclusive ownership
31     void lock(); // blocking
32     bool try_lock();
33     void unlock();
34
35     // Shared ownership
36     void lock_shared(); // blocking
37     bool try_lock_shared();
38     void unlock_shared();
39
40     typedef implementation-defined native_handle_type; // See 30.2.3
41     native_handle_type native_handle(); // See 30.2.3
42 };
43
44 class shared_timed_mutex
45 {
46 public:
47     shared_timed_mutex();
48     ~shared_timed_mutex();
49
50     shared_timed_mutex(const shared_timed_mutex&) = delete;
51     shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
52
53     // Exclusive ownership
54     void lock(); // blocking
55     bool try_lock();
56     template <class Rep, class Period>
57         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
58     template <class Clock, class Duration>
59         bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
60     void unlock();
61
62     // Shared ownership
63     void lock_shared(); // blocking
64     bool try_lock_shared();
65     template <class Rep, class Period>
66         bool
67         try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
68     template <class Clock, class Duration>
69         bool
70         try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
71     void unlock_shared();
72 };
73
74 template <class Mutex>
75 class shared_lock
76 {
77 public:
78     typedef Mutex mutex_type;
79
80     // Shared locking
81     shared_lock() noexcept;
82     explicit shared_lock(mutex_type& m); // blocking
83     shared_lock(mutex_type& m, defer_lock_t) noexcept;
84     shared_lock(mutex_type& m, try_to_lock_t);
85     shared_lock(mutex_type& m, adopt_lock_t);
86     template <class Clock, class Duration>
87         shared_lock(mutex_type& m,
88                     const chrono::time_point<Clock, Duration>& abs_time);
89     template <class Rep, class Period>
90         shared_lock(mutex_type& m,
91                     const chrono::duration<Rep, Period>& rel_time);
92     ~shared_lock();
93
94     shared_lock(shared_lock const&) = delete;
95     shared_lock& operator=(shared_lock const&) = delete;
96
97     shared_lock(shared_lock&& u) noexcept;
98     shared_lock& operator=(shared_lock&& u) noexcept;
99
100     void lock(); // blocking
101     bool try_lock();
102     template <class Rep, class Period>
103         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
104     template <class Clock, class Duration>
105         bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
106     void unlock();
107
108     // Setters
109     void swap(shared_lock& u) noexcept;
110     mutex_type* release() noexcept;
111
112     // Getters
113     bool owns_lock() const noexcept;
114     explicit operator bool () const noexcept;
115     mutex_type* mutex() const noexcept;
116 };
117
118 template <class Mutex>
119     void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
120
121 }  // std
122
123 */
124
125 #include <__config>
126 #include <version>
127
128 _LIBCPP_PUSH_MACROS
129 #include <__undef_macros>
130
131
132 #if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_LIBRARY)
133
134 #include <__mutex_base>
135
136 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
137 #pragma GCC system_header
138 #endif
139
140 #ifdef _LIBCPP_HAS_NO_THREADS
141 #error <shared_mutex> is not supported on this single threaded system
142 #else // !_LIBCPP_HAS_NO_THREADS
143
144 _LIBCPP_BEGIN_NAMESPACE_STD
145
146 struct _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("shared_mutex"))
147 __shared_mutex_base
148 {
149     mutex               __mut_;
150     condition_variable  __gate1_;
151     condition_variable  __gate2_;
152     unsigned            __state_;
153
154     static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
155     static const unsigned __n_readers_ = ~__write_entered_;
156
157     __shared_mutex_base();
158     _LIBCPP_INLINE_VISIBILITY ~__shared_mutex_base() = default;
159
160     __shared_mutex_base(const __shared_mutex_base&) = delete;
161     __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
162
163     // Exclusive ownership
164     void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability()); // blocking
165     bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
166     void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
167
168     // Shared ownership
169     void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_shared_capability()); // blocking
170     bool try_lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_shared_capability(true));
171     void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_shared_capability());
172
173 //     typedef implementation-defined native_handle_type; // See 30.2.3
174 //     native_handle_type native_handle(); // See 30.2.3
175 };
176
177
178 #if _LIBCPP_STD_VER > 14
179 class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_mutex
180 {
181     __shared_mutex_base __base;
182 public:
183     _LIBCPP_INLINE_VISIBILITY shared_mutex() : __base() {}
184     _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default;
185
186     shared_mutex(const shared_mutex&) = delete;
187     shared_mutex& operator=(const shared_mutex&) = delete;
188
189     // Exclusive ownership
190     _LIBCPP_INLINE_VISIBILITY void lock()     { return __base.lock(); }
191     _LIBCPP_INLINE_VISIBILITY bool try_lock() { return __base.try_lock(); }
192     _LIBCPP_INLINE_VISIBILITY void unlock()   { return __base.unlock(); }
193
194     // Shared ownership
195     _LIBCPP_INLINE_VISIBILITY void lock_shared()     { return __base.lock_shared(); }
196     _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() { return __base.try_lock_shared(); }
197     _LIBCPP_INLINE_VISIBILITY void unlock_shared()   { return __base.unlock_shared(); }
198
199 //     typedef __shared_mutex_base::native_handle_type native_handle_type;
200 //     _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() { return __base::unlock_shared(); }
201 };
202 #endif
203
204
205 class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_timed_mutex
206 {
207     __shared_mutex_base __base;
208 public:
209     shared_timed_mutex();
210     _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
211
212     shared_timed_mutex(const shared_timed_mutex&) = delete;
213     shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
214
215     // Exclusive ownership
216     void lock();
217     bool try_lock();
218     template <class _Rep, class _Period>
219         _LIBCPP_INLINE_VISIBILITY
220         bool
221         try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
222         {
223             return try_lock_until(chrono::steady_clock::now() + __rel_time);
224         }
225     template <class _Clock, class _Duration>
226         _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
227         bool
228         try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
229     void unlock();
230
231     // Shared ownership
232     void lock_shared();
233     bool try_lock_shared();
234     template <class _Rep, class _Period>
235         _LIBCPP_INLINE_VISIBILITY
236         bool
237         try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
238         {
239             return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
240         }
241     template <class _Clock, class _Duration>
242         _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
243         bool
244         try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
245     void unlock_shared();
246 };
247
248 template <class _Clock, class _Duration>
249 bool
250 shared_timed_mutex::try_lock_until(
251                         const chrono::time_point<_Clock, _Duration>& __abs_time)
252 {
253     unique_lock<mutex> __lk(__base.__mut_);
254     if (__base.__state_ & __base.__write_entered_)
255     {
256         while (true)
257         {
258             cv_status __status = __base.__gate1_.wait_until(__lk, __abs_time);
259             if ((__base.__state_ & __base.__write_entered_) == 0)
260                 break;
261             if (__status == cv_status::timeout)
262                 return false;
263         }
264     }
265     __base.__state_ |= __base.__write_entered_;
266     if (__base.__state_ & __base.__n_readers_)
267     {
268         while (true)
269         {
270             cv_status __status = __base.__gate2_.wait_until(__lk, __abs_time);
271             if ((__base.__state_ & __base.__n_readers_) == 0)
272                 break;
273             if (__status == cv_status::timeout)
274             {
275                 __base.__state_ &= ~__base.__write_entered_;
276                 __base.__gate1_.notify_all();
277                 return false;
278             }
279         }
280     }
281     return true;
282 }
283
284 template <class _Clock, class _Duration>
285 bool
286 shared_timed_mutex::try_lock_shared_until(
287                         const chrono::time_point<_Clock, _Duration>& __abs_time)
288 {
289     unique_lock<mutex> __lk(__base.__mut_);
290     if ((__base.__state_ & __base.__write_entered_) || (__base.__state_ & __base.__n_readers_) == __base.__n_readers_)
291     {
292         while (true)
293         {
294             cv_status status = __base.__gate1_.wait_until(__lk, __abs_time);
295             if ((__base.__state_ & __base.__write_entered_) == 0 &&
296                                        (__base.__state_ & __base.__n_readers_) < __base.__n_readers_)
297                 break;
298             if (status == cv_status::timeout)
299                 return false;
300         }
301     }
302     unsigned __num_readers = (__base.__state_ & __base.__n_readers_) + 1;
303     __base.__state_ &= ~__base.__n_readers_;
304     __base.__state_ |= __num_readers;
305     return true;
306 }
307
308 template <class _Mutex>
309 class shared_lock
310 {
311 public:
312     typedef _Mutex mutex_type;
313
314 private:
315     mutex_type* __m_;
316     bool __owns_;
317
318 public:
319     _LIBCPP_INLINE_VISIBILITY
320     shared_lock() _NOEXCEPT
321         : __m_(nullptr),
322           __owns_(false)
323         {}
324
325     _LIBCPP_INLINE_VISIBILITY
326     explicit shared_lock(mutex_type& __m)
327         : __m_(_VSTD::addressof(__m)),
328           __owns_(true)
329         {__m_->lock_shared();}
330
331     _LIBCPP_INLINE_VISIBILITY
332     shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
333         : __m_(_VSTD::addressof(__m)),
334           __owns_(false)
335         {}
336
337     _LIBCPP_INLINE_VISIBILITY
338     shared_lock(mutex_type& __m, try_to_lock_t)
339         : __m_(_VSTD::addressof(__m)),
340           __owns_(__m.try_lock_shared())
341         {}
342
343     _LIBCPP_INLINE_VISIBILITY
344     shared_lock(mutex_type& __m, adopt_lock_t)
345         : __m_(_VSTD::addressof(__m)),
346           __owns_(true)
347         {}
348
349     template <class _Clock, class _Duration>
350         _LIBCPP_INLINE_VISIBILITY
351         shared_lock(mutex_type& __m,
352                     const chrono::time_point<_Clock, _Duration>& __abs_time)
353             : __m_(_VSTD::addressof(__m)),
354               __owns_(__m.try_lock_shared_until(__abs_time))
355             {}
356
357     template <class _Rep, class _Period>
358         _LIBCPP_INLINE_VISIBILITY
359         shared_lock(mutex_type& __m,
360                     const chrono::duration<_Rep, _Period>& __rel_time)
361             : __m_(_VSTD::addressof(__m)),
362               __owns_(__m.try_lock_shared_for(__rel_time))
363             {}
364
365     _LIBCPP_INLINE_VISIBILITY
366     ~shared_lock()
367     {
368         if (__owns_)
369             __m_->unlock_shared();
370     }
371
372     shared_lock(shared_lock const&) = delete;
373     shared_lock& operator=(shared_lock const&) = delete;
374
375     _LIBCPP_INLINE_VISIBILITY
376     shared_lock(shared_lock&& __u) _NOEXCEPT
377         : __m_(__u.__m_),
378           __owns_(__u.__owns_)
379         {
380             __u.__m_ = nullptr;
381             __u.__owns_ = false;
382         }
383
384     _LIBCPP_INLINE_VISIBILITY
385     shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
386     {
387         if (__owns_)
388             __m_->unlock_shared();
389         __m_ = nullptr;
390         __owns_ = false;
391         __m_ = __u.__m_;
392         __owns_ = __u.__owns_;
393         __u.__m_ = nullptr;
394         __u.__owns_ = false;
395         return *this;
396     }
397
398     void lock();
399     bool try_lock();
400     template <class Rep, class Period>
401         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
402     template <class Clock, class Duration>
403         bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
404     void unlock();
405
406     // Setters
407     _LIBCPP_INLINE_VISIBILITY
408     void swap(shared_lock& __u) _NOEXCEPT
409     {
410         _VSTD::swap(__m_, __u.__m_);
411         _VSTD::swap(__owns_, __u.__owns_);
412     }
413
414     _LIBCPP_INLINE_VISIBILITY
415     mutex_type* release() _NOEXCEPT
416     {
417         mutex_type* __m = __m_;
418         __m_ = nullptr;
419         __owns_ = false;
420         return __m;
421     }
422
423     // Getters
424     _LIBCPP_INLINE_VISIBILITY
425     bool owns_lock() const _NOEXCEPT {return __owns_;}
426
427     _LIBCPP_INLINE_VISIBILITY
428     explicit operator bool () const _NOEXCEPT {return __owns_;}
429
430     _LIBCPP_INLINE_VISIBILITY
431     mutex_type* mutex() const _NOEXCEPT {return __m_;}
432 };
433
434 template <class _Mutex>
435 void
436 shared_lock<_Mutex>::lock()
437 {
438     if (__m_ == nullptr)
439         __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
440     if (__owns_)
441         __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
442     __m_->lock_shared();
443     __owns_ = true;
444 }
445
446 template <class _Mutex>
447 bool
448 shared_lock<_Mutex>::try_lock()
449 {
450     if (__m_ == nullptr)
451         __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
452     if (__owns_)
453         __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
454     __owns_ = __m_->try_lock_shared();
455     return __owns_;
456 }
457
458 template <class _Mutex>
459 template <class _Rep, class _Period>
460 bool
461 shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
462 {
463     if (__m_ == nullptr)
464         __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
465     if (__owns_)
466         __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
467     __owns_ = __m_->try_lock_shared_for(__d);
468     return __owns_;
469 }
470
471 template <class _Mutex>
472 template <class _Clock, class _Duration>
473 bool
474 shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
475 {
476     if (__m_ == nullptr)
477         __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
478     if (__owns_)
479         __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
480     __owns_ = __m_->try_lock_shared_until(__t);
481     return __owns_;
482 }
483
484 template <class _Mutex>
485 void
486 shared_lock<_Mutex>::unlock()
487 {
488     if (!__owns_)
489         __throw_system_error(EPERM, "shared_lock::unlock: not locked");
490     __m_->unlock_shared();
491     __owns_ = false;
492 }
493
494 template <class _Mutex>
495 inline _LIBCPP_INLINE_VISIBILITY
496 void
497 swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
498     {__x.swap(__y);}
499
500 _LIBCPP_END_NAMESPACE_STD
501
502 #endif  // !_LIBCPP_HAS_NO_THREADS
503
504 #endif  // _LIBCPP_STD_VER > 11
505
506 _LIBCPP_POP_MACROS
507
508 #endif  // _LIBCPP_SHARED_MUTEX