2014-10-01 Edward Smith-Rowland <3dw4rd@verizon.net>
[official-gcc.git] / libstdc++-v3 / include / std / shared_mutex
blob6405f1025ecd0420d83f5dba9a1972302c70e22d
1 // <shared_mutex> -*- C++ -*-
3 // Copyright (C) 2013-2014 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library.  This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23 // <http://www.gnu.org/licenses/>.
25 /** @file include/shared_mutex
26  *  This is a Standard C++ Library header.
27  */
29 #ifndef _GLIBCXX_SHARED_MUTEX
30 #define _GLIBCXX_SHARED_MUTEX 1
32 #pragma GCC system_header
34 #if __cplusplus <= 201103L
35 # include <bits/c++14_warning.h>
36 #else
38 #include <bits/c++config.h>
39 #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
40 # include <mutex>
41 # include <condition_variable>
42 #endif
43 #include <bits/functexcept.h>
45 namespace std _GLIBCXX_VISIBILITY(default)
47 _GLIBCXX_BEGIN_NAMESPACE_VERSION
49   /**
50    * @ingroup mutexes
51    * @{
52    */
54 #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
56 #define __cpp_lib_shared_timed_mutex 201402
58   /// shared_timed_mutex
59   class shared_timed_mutex
60   {
61 #if _GTHREAD_USE_MUTEX_TIMEDLOCK
62     struct _Mutex : mutex, __timed_mutex_impl<_Mutex>
63     {
64       template<typename _Rep, typename _Period>
65         bool
66         try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
67         { return _M_try_lock_for(__rtime); }
69       template<typename _Clock, typename _Duration>
70         bool
71         try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
72         { return _M_try_lock_until(__atime); }
73     };
74 #else
75     typedef mutex _Mutex;
76 #endif
78     // Based on Howard Hinnant's reference implementation from N2406
80     _Mutex              _M_mut;
81     condition_variable  _M_gate1;
82     condition_variable  _M_gate2;
83     unsigned            _M_state;
85     static constexpr unsigned _S_write_entered
86       = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
87     static constexpr unsigned _M_n_readers = ~_S_write_entered;
89   public:
90     shared_timed_mutex() : _M_state(0) {}
92     ~shared_timed_mutex()
93     {
94       _GLIBCXX_DEBUG_ASSERT( _M_state == 0 );
95     }
97     shared_timed_mutex(const shared_timed_mutex&) = delete;
98     shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
100     // Exclusive ownership
102     void
103     lock()
104     {
105       unique_lock<mutex> __lk(_M_mut);
106       while (_M_state & _S_write_entered)
107         _M_gate1.wait(__lk);
108       _M_state |= _S_write_entered;
109       while (_M_state & _M_n_readers)
110         _M_gate2.wait(__lk);
111     }
113     bool
114     try_lock()
115     {
116       unique_lock<mutex> __lk(_M_mut, try_to_lock);
117       if (__lk.owns_lock() && _M_state == 0)
118         {
119           _M_state = _S_write_entered;
120           return true;
121         }
122       return false;
123     }
125 #if _GTHREAD_USE_MUTEX_TIMEDLOCK
126     template<typename _Rep, typename _Period>
127       bool
128       try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
129       {
130         unique_lock<_Mutex> __lk(_M_mut, __rel_time);
131         if (__lk.owns_lock() && _M_state == 0)
132           {
133             _M_state = _S_write_entered;
134             return true;
135           }
136         return false;
137       }
139     template<typename _Clock, typename _Duration>
140       bool
141       try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
142       {
143         unique_lock<_Mutex> __lk(_M_mut, __abs_time);
144         if (__lk.owns_lock() && _M_state == 0)
145           {
146             _M_state = _S_write_entered;
147             return true;
148           }
149         return false;
150       }
151 #endif
153     void
154     unlock()
155     {
156       {
157         lock_guard<_Mutex> __lk(_M_mut);
158         _M_state = 0;
159       }
160       _M_gate1.notify_all();
161     }
163     // Shared ownership
165     void
166     lock_shared()
167     {
168       unique_lock<mutex> __lk(_M_mut);
169       while ((_M_state & _S_write_entered)
170           || (_M_state & _M_n_readers) == _M_n_readers)
171         {
172           _M_gate1.wait(__lk);
173         }
174       unsigned __num_readers = (_M_state & _M_n_readers) + 1;
175       _M_state &= ~_M_n_readers;
176       _M_state |= __num_readers;
177     }
179     bool
180     try_lock_shared()
181     {
182       unique_lock<_Mutex> __lk(_M_mut, try_to_lock);
183       unsigned __num_readers = _M_state & _M_n_readers;
184       if (__lk.owns_lock() && !(_M_state & _S_write_entered)
185           && __num_readers != _M_n_readers)
186         {
187           ++__num_readers;
188           _M_state &= ~_M_n_readers;
189           _M_state |= __num_readers;
190           return true;
191         }
192       return false;
193     }
195 #if _GTHREAD_USE_MUTEX_TIMEDLOCK
196     template<typename _Rep, typename _Period>
197       bool
198       try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
199       {
200         unique_lock<_Mutex> __lk(_M_mut, __rel_time);
201         if (__lk.owns_lock())
202           {
203             unsigned __num_readers = _M_state & _M_n_readers;
204             if (!(_M_state & _S_write_entered)
205                 && __num_readers != _M_n_readers)
206               {
207                 ++__num_readers;
208                 _M_state &= ~_M_n_readers;
209                 _M_state |= __num_readers;
210                 return true;
211               }
212           }
213         return false;
214       }
216     template <typename _Clock, typename _Duration>
217       bool
218       try_lock_shared_until(const chrono::time_point<_Clock,
219                                                      _Duration>& __abs_time)
220       {
221         unique_lock<_Mutex> __lk(_M_mut, __abs_time);
222         if (__lk.owns_lock())
223           {
224             unsigned __num_readers = _M_state & _M_n_readers;
225             if (!(_M_state & _S_write_entered)
226                 && __num_readers != _M_n_readers)
227               {
228                 ++__num_readers;
229                 _M_state &= ~_M_n_readers;
230                 _M_state |= __num_readers;
231                 return true;
232               }
233           }
234         return false;
235       }
236 #endif
238     void
239     unlock_shared()
240     {
241       lock_guard<_Mutex> __lk(_M_mut);
242       unsigned __num_readers = (_M_state & _M_n_readers) - 1;
243       _M_state &= ~_M_n_readers;
244       _M_state |= __num_readers;
245       if (_M_state & _S_write_entered)
246         {
247           if (__num_readers == 0)
248             _M_gate2.notify_one();
249         }
250       else
251         {
252           if (__num_readers == _M_n_readers - 1)
253             _M_gate1.notify_one();
254         }
255     }
256   };
257 #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
259   /// shared_lock
260   template<typename _Mutex>
261     class shared_lock
262     {
263     public:
264       typedef _Mutex mutex_type;
266       // Shared locking
268       shared_lock() noexcept : _M_pm(nullptr), _M_owns(false) { }
270       explicit
271       shared_lock(mutex_type& __m) : _M_pm(&__m), _M_owns(true)
272       { __m.lock_shared(); }
274       shared_lock(mutex_type& __m, defer_lock_t) noexcept
275       : _M_pm(&__m), _M_owns(false) { }
277       shared_lock(mutex_type& __m, try_to_lock_t)
278       : _M_pm(&__m), _M_owns(__m.try_lock_shared()) { }
280       shared_lock(mutex_type& __m, adopt_lock_t)
281       : _M_pm(&__m), _M_owns(true) { }
283       template<typename _Clock, typename _Duration>
284         shared_lock(mutex_type& __m,
285                     const chrono::time_point<_Clock, _Duration>& __abs_time)
286       : _M_pm(&__m), _M_owns(__m.try_lock_shared_until(__abs_time)) { }
288       template<typename _Rep, typename _Period>
289         shared_lock(mutex_type& __m,
290                     const chrono::duration<_Rep, _Period>& __rel_time)
291       : _M_pm(&__m), _M_owns(__m.try_lock_shared_for(__rel_time)) { }
293       ~shared_lock()
294       {
295         if (_M_owns)
296           _M_pm->unlock_shared();
297       }
299       shared_lock(shared_lock const&) = delete;
300       shared_lock& operator=(shared_lock const&) = delete;
302       shared_lock(shared_lock&& __sl) noexcept : shared_lock()
303       { swap(__sl); }
305       shared_lock&
306       operator=(shared_lock&& __sl) noexcept
307       {
308         shared_lock(std::move(__sl)).swap(*this);
309         return *this;
310       }
312       void
313       lock()
314       {
315         _M_lockable();
316         _M_pm->lock_shared();
317         _M_owns = true;
318       }
320       bool
321       try_lock()
322       {
323         _M_lockable();
324         return _M_owns = _M_pm->try_lock_shared();
325       }
327       template<typename _Rep, typename _Period>
328         bool
329         try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
330         {
331           _M_lockable();
332           return _M_owns = _M_pm->try_lock_shared_for(__rel_time);
333         }
335       template<typename _Clock, typename _Duration>
336         bool
337         try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
338         {
339           _M_lockable();
340           return _M_owns = _M_pm->try_lock_shared_until(__abs_time);
341         }
343       void
344       unlock()
345       {
346         if (!_M_owns)
347           __throw_system_error(int(errc::resource_deadlock_would_occur));
348         _M_pm->unlock_shared();
349         _M_owns = false;
350       }
352       // Setters
354       void
355       swap(shared_lock& __u) noexcept
356       {
357         std::swap(_M_pm, __u._M_pm);
358         std::swap(_M_owns, __u._M_owns);
359       }
361       mutex_type*
362       release() noexcept
363       {
364         _M_owns = false;
365         return std::exchange(_M_pm, nullptr);
366       }
368       // Getters
370       bool owns_lock() const noexcept { return _M_owns; }
372       explicit operator bool() const noexcept { return _M_owns; }
374       mutex_type* mutex() const noexcept { return _M_pm; }
376     private:
377       void
378       _M_lockable() const
379       {
380         if (_M_pm == nullptr)
381           __throw_system_error(int(errc::operation_not_permitted));
382         if (_M_owns)
383           __throw_system_error(int(errc::resource_deadlock_would_occur));
384       }
386       mutex_type*       _M_pm;
387       bool              _M_owns;
388     };
390   /// Swap specialization for shared_lock
391   template<typename _Mutex>
392     void
393     swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) noexcept
394     { __x.swap(__y); }
396   // @} group mutexes
397 _GLIBCXX_END_NAMESPACE_VERSION
398 } // namespace
400 #endif // C++14
402 #endif // _GLIBCXX_SHARED_MUTEX