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
19namespace std
20{
21
22class shared_mutex      // C++17
23{
24public:
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
45class shared_timed_mutex
46{
47public:
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
75template <class Mutex>
76class shared_lock
77{
78public:
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
119template <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
146struct _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
178class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_mutex
179{
180    __shared_mutex_base __base;
181public:
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
204class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_timed_mutex
205{
206    __shared_mutex_base __base;
207public:
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
247template <class _Clock, class _Duration>
248bool
249shared_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
283template <class _Clock, class _Duration>
284bool
285shared_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
307template <class _Mutex>
308class shared_lock
309{
310public:
311    typedef _Mutex mutex_type;
312
313private:
314    mutex_type* __m_;
315    bool __owns_;
316
317public:
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
433template <class _Mutex>
434void
435shared_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
445template <class _Mutex>
446bool
447shared_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
457template <class _Mutex>
458template <class _Rep, class _Period>
459bool
460shared_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
470template <class _Mutex>
471template <class _Clock, class _Duration>
472bool
473shared_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
483template <class _Mutex>
484void
485shared_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
493template <class _Mutex>
494inline _LIBCPP_INLINE_VISIBILITY
495void
496swap(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
508