• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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#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
144struct _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
176class _LIBCPP_TYPE_VIS shared_mutex
177{
178	__shared_mutex_base __base;
179public:
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
202class _LIBCPP_TYPE_VIS shared_timed_mutex
203{
204	__shared_mutex_base __base;
205public:
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
245template <class _Clock, class _Duration>
246bool
247shared_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
281template <class _Clock, class _Duration>
282bool
283shared_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
305template <class _Mutex>
306class shared_lock
307{
308public:
309    typedef _Mutex mutex_type;
310
311private:
312    mutex_type* __m_;
313    bool __owns_;
314
315public:
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
431template <class _Mutex>
432void
433shared_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
443template <class _Mutex>
444bool
445shared_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
455template <class _Mutex>
456template <class _Rep, class _Period>
457bool
458shared_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
468template <class _Mutex>
469template <class _Clock, class _Duration>
470bool
471shared_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
481template <class _Mutex>
482void
483shared_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
491template <class _Mutex>
492inline _LIBCPP_INLINE_VISIBILITY
493void
494swap(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
504