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