Update gcc-50 to SVN version 221423
[dragonfly.git] / contrib / gcc-5.0 / libstdc++-v3 / include / std / shared_mutex
1 // <shared_mutex> -*- C++ -*-
2
3 // Copyright (C) 2013-2015 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 #if defined(__GTHREADS_CXX0X)
61     typedef chrono::system_clock        __clock_t;
62
63     pthread_rwlock_t                    _M_rwlock;
64
65   public:
66     shared_timed_mutex()
67     {
68       int __ret = pthread_rwlock_init(&_M_rwlock, NULL);
69       if (__ret == ENOMEM)
70         throw bad_alloc();
71       else if (__ret == EAGAIN)
72         __throw_system_error(int(errc::resource_unavailable_try_again));
73       else if (__ret == EPERM)
74         __throw_system_error(int(errc::operation_not_permitted));
75       // Errors not handled: EBUSY, EINVAL
76       _GLIBCXX_DEBUG_ASSERT(__ret == 0);
77     }
78
79     ~shared_timed_mutex()
80     {
81       int __ret __attribute((__unused__)) = pthread_rwlock_destroy(&_M_rwlock);
82       // Errors not handled: EBUSY, EINVAL
83       _GLIBCXX_DEBUG_ASSERT(__ret == 0);
84     }
85
86     shared_timed_mutex(const shared_timed_mutex&) = delete;
87     shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
88
89     // Exclusive ownership
90
91     void
92     lock()
93     {
94       int __ret = pthread_rwlock_wrlock(&_M_rwlock);
95       if (__ret == EDEADLK)
96         __throw_system_error(int(errc::resource_deadlock_would_occur));
97       // Errors not handled: EINVAL
98       _GLIBCXX_DEBUG_ASSERT(__ret == 0);
99     }
100
101     bool
102     try_lock()
103     {
104       int __ret = pthread_rwlock_trywrlock(&_M_rwlock);
105       if (__ret == EBUSY) return false;
106       // Errors not handled: EINVAL
107       _GLIBCXX_DEBUG_ASSERT(__ret == 0);
108       return true;
109     }
110
111 #if _GTHREAD_USE_MUTEX_TIMEDLOCK
112     template<typename _Rep, typename _Period>
113       bool
114       try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
115       {
116         return try_lock_until(__clock_t::now() + __rel_time);
117       }
118
119     template<typename _Duration>
120       bool
121       try_lock_until(const chrono::time_point<__clock_t, _Duration>& __atime)
122       {
123         auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
124         auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
125
126         __gthread_time_t __ts =
127           {
128             static_cast<std::time_t>(__s.time_since_epoch().count()),
129             static_cast<long>(__ns.count())
130           };
131
132         int __ret = pthread_rwlock_timedwrlock(&_M_rwlock, &__ts);
133         // On self-deadlock, we just fail to acquire the lock.  Technically,
134         // the program violated the precondition.
135         if (__ret == ETIMEDOUT || __ret == EDEADLK)
136           return false;
137         // Errors not handled: EINVAL
138         _GLIBCXX_DEBUG_ASSERT(__ret == 0);
139         return true;
140       }
141
142     template<typename _Clock, typename _Duration>
143       bool
144       try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
145       {
146         // DR 887 - Sync unknown clock to known clock.
147         const typename _Clock::time_point __c_entry = _Clock::now();
148         const __clock_t::time_point __s_entry = __clock_t::now();
149         const auto __delta = __abs_time - __c_entry;
150         const auto __s_atime = __s_entry + __delta;
151         return try_lock_until(__s_atime);
152       }
153 #endif
154
155     void
156     unlock()
157     {
158       int __ret __attribute((__unused__)) = pthread_rwlock_unlock(&_M_rwlock);
159       // Errors not handled: EPERM, EBUSY, EINVAL
160       _GLIBCXX_DEBUG_ASSERT(__ret == 0);
161     }
162
163     // Shared ownership
164
165     void
166     lock_shared()
167     {
168       int __ret = pthread_rwlock_rdlock(&_M_rwlock);
169       if (__ret == EDEADLK)
170         __throw_system_error(int(errc::resource_deadlock_would_occur));
171       if (__ret == EAGAIN)
172         // Maximum number of read locks has been exceeded.
173         __throw_system_error(int(errc::device_or_resource_busy));
174       // Errors not handled: EINVAL
175       _GLIBCXX_DEBUG_ASSERT(__ret == 0);
176     }
177
178     bool
179     try_lock_shared()
180     {
181       int __ret = pthread_rwlock_tryrdlock(&_M_rwlock);
182       // If the maximum number of read locks has been exceeded, we just fail
183       // to acquire the lock.  Unlike for lock(), we are not allowed to throw
184       // an exception.
185       if (__ret == EBUSY || __ret == EAGAIN) return false;
186       // Errors not handled: EINVAL
187       _GLIBCXX_DEBUG_ASSERT(__ret == 0);
188       return true;
189     }
190
191 #if _GTHREAD_USE_MUTEX_TIMEDLOCK
192     template<typename _Rep, typename _Period>
193       bool
194       try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
195       {
196         return try_lock_shared_until(__clock_t::now() + __rel_time);
197       }
198
199     template<typename _Duration>
200       bool
201       try_lock_shared_until(const chrono::time_point<__clock_t,
202                             _Duration>& __atime)
203       {
204         auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
205         auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
206
207         __gthread_time_t __ts =
208           {
209             static_cast<std::time_t>(__s.time_since_epoch().count()),
210             static_cast<long>(__ns.count())
211           };
212
213         int __ret = pthread_rwlock_timedrdlock(&_M_rwlock, &__ts);
214         // If the maximum number of read locks has been exceeded, or we would
215         // deadlock, we just fail to acquire the lock.  Unlike for lock(),
216         // we are not allowed to throw an exception.
217         if (__ret == ETIMEDOUT || __ret == EAGAIN || __ret == EDEADLK)
218           return false;
219         // Errors not handled: EINVAL
220         _GLIBCXX_DEBUG_ASSERT(__ret == 0);
221         return true;
222       }
223
224     template<typename _Clock, typename _Duration>
225       bool
226       try_lock_shared_until(const chrono::time_point<_Clock,
227                             _Duration>& __abs_time)
228       {
229         // DR 887 - Sync unknown clock to known clock.
230         const typename _Clock::time_point __c_entry = _Clock::now();
231         const __clock_t::time_point __s_entry = __clock_t::now();
232         const auto __delta = __abs_time - __c_entry;
233         const auto __s_atime = __s_entry + __delta;
234         return try_lock_shared_until(__s_atime);
235       }
236 #endif
237
238     void
239     unlock_shared()
240     {
241       unlock();
242     }
243
244 #else // defined(__GTHREADS_CXX0X)
245
246 #if _GTHREAD_USE_MUTEX_TIMEDLOCK
247     struct _Mutex : mutex, __timed_mutex_impl<_Mutex>
248     {
249       template<typename _Rep, typename _Period>
250         bool
251         try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
252         { return _M_try_lock_for(__rtime); }
253
254       template<typename _Clock, typename _Duration>
255         bool
256         try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
257         { return _M_try_lock_until(__atime); }
258     };
259 #else
260     typedef mutex _Mutex;
261 #endif
262
263     // Based on Howard Hinnant's reference implementation from N2406
264
265     _Mutex              _M_mut;
266     condition_variable  _M_gate1;
267     condition_variable  _M_gate2;
268     unsigned            _M_state;
269
270     static constexpr unsigned _S_write_entered
271       = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
272     static constexpr unsigned _M_n_readers = ~_S_write_entered;
273
274   public:
275     shared_timed_mutex() : _M_state(0) {}
276
277     ~shared_timed_mutex()
278     {
279       _GLIBCXX_DEBUG_ASSERT( _M_state == 0 );
280     }
281
282     shared_timed_mutex(const shared_timed_mutex&) = delete;
283     shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
284
285     // Exclusive ownership
286
287     void
288     lock()
289     {
290       unique_lock<mutex> __lk(_M_mut);
291       while (_M_state & _S_write_entered)
292         _M_gate1.wait(__lk);
293       _M_state |= _S_write_entered;
294       while (_M_state & _M_n_readers)
295         _M_gate2.wait(__lk);
296     }
297
298     bool
299     try_lock()
300     {
301       unique_lock<mutex> __lk(_M_mut, try_to_lock);
302       if (__lk.owns_lock() && _M_state == 0)
303         {
304           _M_state = _S_write_entered;
305           return true;
306         }
307       return false;
308     }
309
310 #if _GTHREAD_USE_MUTEX_TIMEDLOCK
311     template<typename _Rep, typename _Period>
312       bool
313       try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
314       {
315         unique_lock<_Mutex> __lk(_M_mut, __rel_time);
316         if (__lk.owns_lock() && _M_state == 0)
317           {
318             _M_state = _S_write_entered;
319             return true;
320           }
321         return false;
322       }
323
324     template<typename _Clock, typename _Duration>
325       bool
326       try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
327       {
328         unique_lock<_Mutex> __lk(_M_mut, __abs_time);
329         if (__lk.owns_lock() && _M_state == 0)
330           {
331             _M_state = _S_write_entered;
332             return true;
333           }
334         return false;
335       }
336 #endif
337
338     void
339     unlock()
340     {
341       {
342         lock_guard<_Mutex> __lk(_M_mut);
343         _M_state = 0;
344       }
345       _M_gate1.notify_all();
346     }
347
348     // Shared ownership
349
350     void
351     lock_shared()
352     {
353       unique_lock<mutex> __lk(_M_mut);
354       while ((_M_state & _S_write_entered)
355           || (_M_state & _M_n_readers) == _M_n_readers)
356         {
357           _M_gate1.wait(__lk);
358         }
359       unsigned __num_readers = (_M_state & _M_n_readers) + 1;
360       _M_state &= ~_M_n_readers;
361       _M_state |= __num_readers;
362     }
363
364     bool
365     try_lock_shared()
366     {
367       unique_lock<_Mutex> __lk(_M_mut, try_to_lock);
368       unsigned __num_readers = _M_state & _M_n_readers;
369       if (__lk.owns_lock() && !(_M_state & _S_write_entered)
370           && __num_readers != _M_n_readers)
371         {
372           ++__num_readers;
373           _M_state &= ~_M_n_readers;
374           _M_state |= __num_readers;
375           return true;
376         }
377       return false;
378     }
379
380 #if _GTHREAD_USE_MUTEX_TIMEDLOCK
381     template<typename _Rep, typename _Period>
382       bool
383       try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
384       {
385         unique_lock<_Mutex> __lk(_M_mut, __rel_time);
386         if (__lk.owns_lock())
387           {
388             unsigned __num_readers = _M_state & _M_n_readers;
389             if (!(_M_state & _S_write_entered)
390                 && __num_readers != _M_n_readers)
391               {
392                 ++__num_readers;
393                 _M_state &= ~_M_n_readers;
394                 _M_state |= __num_readers;
395                 return true;
396               }
397           }
398         return false;
399       }
400
401     template <typename _Clock, typename _Duration>
402       bool
403       try_lock_shared_until(const chrono::time_point<_Clock,
404                                                      _Duration>& __abs_time)
405       {
406         unique_lock<_Mutex> __lk(_M_mut, __abs_time);
407         if (__lk.owns_lock())
408           {
409             unsigned __num_readers = _M_state & _M_n_readers;
410             if (!(_M_state & _S_write_entered)
411                 && __num_readers != _M_n_readers)
412               {
413                 ++__num_readers;
414                 _M_state &= ~_M_n_readers;
415                 _M_state |= __num_readers;
416                 return true;
417               }
418           }
419         return false;
420       }
421 #endif
422
423     void
424     unlock_shared()
425     {
426       lock_guard<_Mutex> __lk(_M_mut);
427       unsigned __num_readers = (_M_state & _M_n_readers) - 1;
428       _M_state &= ~_M_n_readers;
429       _M_state |= __num_readers;
430       if (_M_state & _S_write_entered)
431         {
432           if (__num_readers == 0)
433             _M_gate2.notify_one();
434         }
435       else
436         {
437           if (__num_readers == _M_n_readers - 1)
438             _M_gate1.notify_one();
439         }
440     }
441 #endif // !defined(__GTHREADS_CXX0X)
442   };
443 #endif // _GLIBCXX_HAS_GTHREADS
444
445   /// shared_lock
446   template<typename _Mutex>
447     class shared_lock
448     {
449     public:
450       typedef _Mutex mutex_type;
451
452       // Shared locking
453
454       shared_lock() noexcept : _M_pm(nullptr), _M_owns(false) { }
455
456       explicit
457       shared_lock(mutex_type& __m) : _M_pm(&__m), _M_owns(true)
458       { __m.lock_shared(); }
459
460       shared_lock(mutex_type& __m, defer_lock_t) noexcept
461       : _M_pm(&__m), _M_owns(false) { }
462
463       shared_lock(mutex_type& __m, try_to_lock_t)
464       : _M_pm(&__m), _M_owns(__m.try_lock_shared()) { }
465
466       shared_lock(mutex_type& __m, adopt_lock_t)
467       : _M_pm(&__m), _M_owns(true) { }
468
469       template<typename _Clock, typename _Duration>
470         shared_lock(mutex_type& __m,
471                     const chrono::time_point<_Clock, _Duration>& __abs_time)
472       : _M_pm(&__m), _M_owns(__m.try_lock_shared_until(__abs_time)) { }
473
474       template<typename _Rep, typename _Period>
475         shared_lock(mutex_type& __m,
476                     const chrono::duration<_Rep, _Period>& __rel_time)
477       : _M_pm(&__m), _M_owns(__m.try_lock_shared_for(__rel_time)) { }
478
479       ~shared_lock()
480       {
481         if (_M_owns)
482           _M_pm->unlock_shared();
483       }
484
485       shared_lock(shared_lock const&) = delete;
486       shared_lock& operator=(shared_lock const&) = delete;
487
488       shared_lock(shared_lock&& __sl) noexcept : shared_lock()
489       { swap(__sl); }
490
491       shared_lock&
492       operator=(shared_lock&& __sl) noexcept
493       {
494         shared_lock(std::move(__sl)).swap(*this);
495         return *this;
496       }
497
498       void
499       lock()
500       {
501         _M_lockable();
502         _M_pm->lock_shared();
503         _M_owns = true;
504       }
505
506       bool
507       try_lock()
508       {
509         _M_lockable();
510         return _M_owns = _M_pm->try_lock_shared();
511       }
512
513       template<typename _Rep, typename _Period>
514         bool
515         try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
516         {
517           _M_lockable();
518           return _M_owns = _M_pm->try_lock_shared_for(__rel_time);
519         }
520
521       template<typename _Clock, typename _Duration>
522         bool
523         try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
524         {
525           _M_lockable();
526           return _M_owns = _M_pm->try_lock_shared_until(__abs_time);
527         }
528
529       void
530       unlock()
531       {
532         if (!_M_owns)
533           __throw_system_error(int(errc::resource_deadlock_would_occur));
534         _M_pm->unlock_shared();
535         _M_owns = false;
536       }
537
538       // Setters
539
540       void
541       swap(shared_lock& __u) noexcept
542       {
543         std::swap(_M_pm, __u._M_pm);
544         std::swap(_M_owns, __u._M_owns);
545       }
546
547       mutex_type*
548       release() noexcept
549       {
550         _M_owns = false;
551         return std::exchange(_M_pm, nullptr);
552       }
553
554       // Getters
555
556       bool owns_lock() const noexcept { return _M_owns; }
557
558       explicit operator bool() const noexcept { return _M_owns; }
559
560       mutex_type* mutex() const noexcept { return _M_pm; }
561
562     private:
563       void
564       _M_lockable() const
565       {
566         if (_M_pm == nullptr)
567           __throw_system_error(int(errc::operation_not_permitted));
568         if (_M_owns)
569           __throw_system_error(int(errc::resource_deadlock_would_occur));
570       }
571
572       mutex_type*       _M_pm;
573       bool              _M_owns;
574     };
575
576   /// Swap specialization for shared_lock
577   template<typename _Mutex>
578     void
579     swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) noexcept
580     { __x.swap(__y); }
581
582 #endif // _GLIBCXX_USE_C99_STDINT_TR1
583
584   // @} group mutexes
585 _GLIBCXX_END_NAMESPACE_VERSION
586 } // namespace
587
588 #endif // C++14
589
590 #endif // _GLIBCXX_SHARED_MUTEX