]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4re-core/libstdc++-v3/contrib/libstdc++-v3-4.9/include/std/shared_mutex
Update
[l4.git] / l4 / pkg / l4re-core / libstdc++-v3 / contrib / libstdc++-v3-4.9 / include / std / shared_mutex
1 // <shared_mutex> -*- C++ -*-
2
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.
10
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.
15
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.
19
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/>.
24
25 /** @file include/shared_mutex
26  *  This is a Standard C++ Library header.
27  */
28
29 #ifndef _GLIBCXX_SHARED_MUTEX
30 #define _GLIBCXX_SHARED_MUTEX 1
31
32 #pragma GCC system_header
33
34 #if __cplusplus <= 201103L
35 # include <bits/c++14_warning.h>
36 #else
37
38 #include <bits/c++config.h>
39 #include <mutex>
40 #include <condition_variable>
41 #include <bits/functexcept.h>
42
43 namespace std _GLIBCXX_VISIBILITY(default)
44 {
45 _GLIBCXX_BEGIN_NAMESPACE_VERSION
46
47   /**
48    * @ingroup mutexes
49    * @{
50    */
51
52 #ifdef _GLIBCXX_USE_C99_STDINT_TR1
53 #ifdef _GLIBCXX_HAS_GTHREADS
54
55 #define __cpp_lib_shared_timed_mutex 201402
56
57   /// shared_timed_mutex
58   class shared_timed_mutex
59   {
60     // Must use the same clock as condition_variable
61     typedef chrono::system_clock        __clock_t;
62
63     // Based on Howard Hinnant's reference implementation from N2406.
64
65     // The high bit of _M_state is the write-entered flag which is set to
66     // indicate a writer has taken the lock or is queuing to take the lock.
67     // The remaining bits are the count of reader locks.
68     //
69     // To take a reader lock, block on gate1 while the write-entered flag is
70     // set or the maximum number of reader locks is held, then increment the
71     // reader lock count.
72     // To release, decrement the count, then if the write-entered flag is set
73     // and the count is zero then signal gate2 to wake a queued writer,
74     // otherwise if the maximum number of reader locks was held signal gate1
75     // to wake a reader.
76     //
77     // To take a writer lock, block on gate1 while the write-entered flag is
78     // set, then set the write-entered flag to start queueing, then block on
79     // gate2 while the number of reader locks is non-zero.
80     // To release, unset the write-entered flag and signal gate1 to wake all
81     // blocked readers and writers.
82     //
83     // This means that when no reader locks are held readers and writers get
84     // equal priority. When one or more reader locks is held a writer gets
85     // priority and no more reader locks can be taken while the writer is
86     // queued.
87
88     // Only locked when accessing _M_state or waiting on condition variables.
89     mutex               _M_mut;
90     // Used to block while write-entered is set or reader count at maximum.
91     condition_variable  _M_gate1;
92     // Used to block queued writers while reader count is non-zero.
93     condition_variable  _M_gate2;
94     // The write-entered flag and reader count.
95     unsigned            _M_state;
96
97     static constexpr unsigned _S_write_entered
98       = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
99     static constexpr unsigned _S_max_readers = ~_S_write_entered;
100
101     // Test whether the write-entered flag is set. _M_mut must be locked.
102     bool _M_write_entered() const { return _M_state & _S_write_entered; }
103
104     // The number of reader locks currently held. _M_mut must be locked.
105     unsigned _M_readers() const { return _M_state & _S_max_readers; }
106
107   public:
108     shared_timed_mutex() : _M_state(0) {}
109
110     ~shared_timed_mutex()
111     {
112       _GLIBCXX_DEBUG_ASSERT( _M_state == 0 );
113     }
114
115     shared_timed_mutex(const shared_timed_mutex&) = delete;
116     shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
117
118     // Exclusive ownership
119
120     void
121     lock()
122     {
123       unique_lock<mutex> __lk(_M_mut);
124       // Wait until we can set the write-entered flag.
125       _M_gate1.wait(__lk, [=]{ return !_M_write_entered(); });
126       _M_state |= _S_write_entered;
127       // Then wait until there are no more readers.
128       _M_gate2.wait(__lk, [=]{ return _M_readers() == 0; });
129     }
130
131     bool
132     try_lock()
133     {
134       unique_lock<mutex> __lk(_M_mut, try_to_lock);
135       if (__lk.owns_lock() && _M_state == 0)
136         {
137           _M_state = _S_write_entered;
138           return true;
139         }
140       return false;
141     }
142
143     template<typename _Rep, typename _Period>
144       bool
145       try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
146       {
147         return try_lock_until(__clock_t::now() + __rel_time);
148       }
149
150     template<typename _Clock, typename _Duration>
151       bool
152       try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
153       {
154         unique_lock<mutex> __lk(_M_mut);
155         if (!_M_gate1.wait_until(__lk, __abs_time,
156                                  [=]{ return !_M_write_entered(); }))
157           {
158             return false;
159           }
160         _M_state |= _S_write_entered;
161         if (!_M_gate2.wait_until(__lk, __abs_time,
162                                  [=]{ return _M_readers() == 0; }))
163           {
164             _M_state ^= _S_write_entered;
165             // Wake all threads blocked while the write-entered flag was set.
166             _M_gate1.notify_all();
167             return false;
168           }
169         return true;
170       }
171
172     void
173     unlock()
174     {
175       lock_guard<mutex> __lk(_M_mut);
176       _GLIBCXX_DEBUG_ASSERT( _M_write_entered() );
177       _M_state = 0;
178       // call notify_all() while mutex is held so that another thread can't
179       // lock and unlock the mutex then destroy *this before we make the call.
180       _M_gate1.notify_all();
181     }
182
183     // Shared ownership
184
185     void
186     lock_shared()
187     {
188       unique_lock<mutex> __lk(_M_mut);
189       _M_gate1.wait(__lk, [=]{ return _M_state < _S_max_readers; });
190       ++_M_state;
191     }
192
193     bool
194     try_lock_shared()
195     {
196       unique_lock<mutex> __lk(_M_mut, try_to_lock);
197       if (!__lk.owns_lock())
198         return false;
199       if (_M_state < _S_max_readers)
200         {
201           ++_M_state;
202           return true;
203         }
204       return false;
205     }
206
207     template<typename _Rep, typename _Period>
208       bool
209       try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
210       {
211         return try_lock_shared_until(__clock_t::now() + __rel_time);
212       }
213
214     template <typename _Clock, typename _Duration>
215       bool
216       try_lock_shared_until(const chrono::time_point<_Clock,
217                                                      _Duration>& __abs_time)
218       {
219         unique_lock<mutex> __lk(_M_mut);
220         if (!_M_gate1.wait_until(__lk, __abs_time,
221                                  [=]{ return _M_state < _S_max_readers; }))
222           {
223             return false;
224           }
225         ++_M_state;
226         return true;
227       }
228
229     void
230     unlock_shared()
231     {
232       lock_guard<mutex> __lk(_M_mut);
233       _GLIBCXX_DEBUG_ASSERT( _M_readers() > 0 );
234       auto __prev = _M_state--;
235       if (_M_write_entered())
236         {
237           // Wake the queued writer if there are no more readers.
238           if (_M_readers() == 0)
239             _M_gate2.notify_one();
240           // No need to notify gate1 because we give priority to the queued
241           // writer, and that writer will eventually notify gate1 after it
242           // clears the write-entered flag.
243         }
244       else
245         {
246           // Wake any thread that was blocked on reader overflow.
247           if (__prev == _S_max_readers)
248             _M_gate1.notify_one();
249         }
250     }
251   };
252 #endif // _GLIBCXX_HAS_GTHREADS
253
254   /// shared_lock
255   template<typename _Mutex>
256     class shared_lock
257     {
258     public:
259       typedef _Mutex mutex_type;
260
261       // Shared locking
262
263       shared_lock() noexcept : _M_pm(nullptr), _M_owns(false) { }
264
265       explicit
266       shared_lock(mutex_type& __m) : _M_pm(&__m), _M_owns(true)
267       { __m.lock_shared(); }
268
269       shared_lock(mutex_type& __m, defer_lock_t) noexcept
270       : _M_pm(&__m), _M_owns(false) { }
271
272       shared_lock(mutex_type& __m, try_to_lock_t)
273       : _M_pm(&__m), _M_owns(__m.try_lock_shared()) { }
274
275       shared_lock(mutex_type& __m, adopt_lock_t)
276       : _M_pm(&__m), _M_owns(true) { }
277
278       template<typename _Clock, typename _Duration>
279         shared_lock(mutex_type& __m,
280                     const chrono::time_point<_Clock, _Duration>& __abs_time)
281       : _M_pm(&__m), _M_owns(__m.try_lock_shared_until(__abs_time)) { }
282
283       template<typename _Rep, typename _Period>
284         shared_lock(mutex_type& __m,
285                     const chrono::duration<_Rep, _Period>& __rel_time)
286       : _M_pm(&__m), _M_owns(__m.try_lock_shared_for(__rel_time)) { }
287
288       ~shared_lock()
289       {
290         if (_M_owns)
291           _M_pm->unlock_shared();
292       }
293
294       shared_lock(shared_lock const&) = delete;
295       shared_lock& operator=(shared_lock const&) = delete;
296
297       shared_lock(shared_lock&& __sl) noexcept : shared_lock()
298       { swap(__sl); }
299
300       shared_lock&
301       operator=(shared_lock&& __sl) noexcept
302       {
303         shared_lock(std::move(__sl)).swap(*this);
304         return *this;
305       }
306
307       void
308       lock()
309       {
310         _M_lockable();
311         _M_pm->lock_shared();
312         _M_owns = true;
313       }
314
315       bool
316       try_lock()
317       {
318         _M_lockable();
319         return _M_owns = _M_pm->try_lock_shared();
320       }
321
322       template<typename _Rep, typename _Period>
323         bool
324         try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
325         {
326           _M_lockable();
327           return _M_owns = _M_pm->try_lock_shared_for(__rel_time);
328         }
329
330       template<typename _Clock, typename _Duration>
331         bool
332         try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
333         {
334           _M_lockable();
335           return _M_owns = _M_pm->try_lock_shared_until(__abs_time);
336         }
337
338       void
339       unlock()
340       {
341         if (!_M_owns)
342           __throw_system_error(int(errc::resource_deadlock_would_occur));
343         _M_pm->unlock_shared();
344         _M_owns = false;
345       }
346
347       // Setters
348
349       void
350       swap(shared_lock& __u) noexcept
351       {
352         std::swap(_M_pm, __u._M_pm);
353         std::swap(_M_owns, __u._M_owns);
354       }
355
356       mutex_type*
357       release() noexcept
358       {
359         _M_owns = false;
360         return std::exchange(_M_pm, nullptr);
361       }
362
363       // Getters
364
365       bool owns_lock() const noexcept { return _M_owns; }
366
367       explicit operator bool() const noexcept { return _M_owns; }
368
369       mutex_type* mutex() const noexcept { return _M_pm; }
370
371     private:
372       void
373       _M_lockable() const
374       {
375         if (_M_pm == nullptr)
376           __throw_system_error(int(errc::operation_not_permitted));
377         if (_M_owns)
378           __throw_system_error(int(errc::resource_deadlock_would_occur));
379       }
380
381       mutex_type*       _M_pm;
382       bool              _M_owns;
383     };
384
385   /// Swap specialization for shared_lock
386   template<typename _Mutex>
387     void
388     swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) noexcept
389     { __x.swap(__y); }
390
391 #endif // _GLIBCXX_USE_C99_STDINT_TR1
392
393   // @} group mutexes
394 _GLIBCXX_END_NAMESPACE_VERSION
395 } // namespace
396
397 #endif // C++14
398
399 #endif // _GLIBCXX_SHARED_MUTEX