xref: /dflybsd-src/contrib/gcc-8.0/libstdc++-v3/include/ext/concurrence.h (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
1*38fd1498Szrj // Support for concurrent programing -*- C++ -*-
2*38fd1498Szrj 
3*38fd1498Szrj // Copyright (C) 2003-2018 Free Software Foundation, Inc.
4*38fd1498Szrj //
5*38fd1498Szrj // This file is part of the GNU ISO C++ Library.  This library is free
6*38fd1498Szrj // software; you can redistribute it and/or modify it under the
7*38fd1498Szrj // terms of the GNU General Public License as published by the
8*38fd1498Szrj // Free Software Foundation; either version 3, or (at your option)
9*38fd1498Szrj // any later version.
10*38fd1498Szrj 
11*38fd1498Szrj // This library is distributed in the hope that it will be useful,
12*38fd1498Szrj // but WITHOUT ANY WARRANTY; without even the implied warranty of
13*38fd1498Szrj // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*38fd1498Szrj // GNU General Public License for more details.
15*38fd1498Szrj 
16*38fd1498Szrj // Under Section 7 of GPL version 3, you are granted additional
17*38fd1498Szrj // permissions described in the GCC Runtime Library Exception, version
18*38fd1498Szrj // 3.1, as published by the Free Software Foundation.
19*38fd1498Szrj 
20*38fd1498Szrj // You should have received a copy of the GNU General Public License and
21*38fd1498Szrj // a copy of the GCC Runtime Library Exception along with this program;
22*38fd1498Szrj // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23*38fd1498Szrj // <http://www.gnu.org/licenses/>.
24*38fd1498Szrj 
25*38fd1498Szrj /** @file ext/concurrence.h
26*38fd1498Szrj  *  This file is a GNU extension to the Standard C++ Library.
27*38fd1498Szrj  */
28*38fd1498Szrj 
29*38fd1498Szrj #ifndef _CONCURRENCE_H
30*38fd1498Szrj #define _CONCURRENCE_H 1
31*38fd1498Szrj 
32*38fd1498Szrj #pragma GCC system_header
33*38fd1498Szrj 
34*38fd1498Szrj #include <exception>
35*38fd1498Szrj #include <bits/gthr.h>
36*38fd1498Szrj #include <bits/functexcept.h>
37*38fd1498Szrj #include <bits/cpp_type_traits.h>
38*38fd1498Szrj #include <ext/type_traits.h>
39*38fd1498Szrj 
_GLIBCXX_VISIBILITY(default)40*38fd1498Szrj namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
41*38fd1498Szrj {
42*38fd1498Szrj _GLIBCXX_BEGIN_NAMESPACE_VERSION
43*38fd1498Szrj 
44*38fd1498Szrj   // Available locking policies:
45*38fd1498Szrj   // _S_single    single-threaded code that doesn't need to be locked.
46*38fd1498Szrj   // _S_mutex     multi-threaded code that requires additional support
47*38fd1498Szrj   //              from gthr.h or abstraction layers in concurrence.h.
48*38fd1498Szrj   // _S_atomic    multi-threaded code using atomic operations.
49*38fd1498Szrj   enum _Lock_policy { _S_single, _S_mutex, _S_atomic };
50*38fd1498Szrj 
51*38fd1498Szrj   // Compile time constant that indicates prefered locking policy in
52*38fd1498Szrj   // the current configuration.
53*38fd1498Szrj   static const _Lock_policy __default_lock_policy =
54*38fd1498Szrj #ifdef __GTHREADS
55*38fd1498Szrj #if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) \
56*38fd1498Szrj      && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4))
57*38fd1498Szrj   _S_atomic;
58*38fd1498Szrj #else
59*38fd1498Szrj   _S_mutex;
60*38fd1498Szrj #endif
61*38fd1498Szrj #else
62*38fd1498Szrj   _S_single;
63*38fd1498Szrj #endif
64*38fd1498Szrj 
65*38fd1498Szrj   // NB: As this is used in libsupc++, need to only depend on
66*38fd1498Szrj   // exception. No stdexception classes, no use of std::string.
67*38fd1498Szrj   class __concurrence_lock_error : public std::exception
68*38fd1498Szrj   {
69*38fd1498Szrj   public:
70*38fd1498Szrj     virtual char const*
71*38fd1498Szrj     what() const throw()
72*38fd1498Szrj     { return "__gnu_cxx::__concurrence_lock_error"; }
73*38fd1498Szrj   };
74*38fd1498Szrj 
75*38fd1498Szrj   class __concurrence_unlock_error : public std::exception
76*38fd1498Szrj   {
77*38fd1498Szrj   public:
78*38fd1498Szrj     virtual char const*
79*38fd1498Szrj     what() const throw()
80*38fd1498Szrj     { return "__gnu_cxx::__concurrence_unlock_error"; }
81*38fd1498Szrj   };
82*38fd1498Szrj 
83*38fd1498Szrj   class __concurrence_broadcast_error : public std::exception
84*38fd1498Szrj   {
85*38fd1498Szrj   public:
86*38fd1498Szrj     virtual char const*
87*38fd1498Szrj     what() const throw()
88*38fd1498Szrj     { return "__gnu_cxx::__concurrence_broadcast_error"; }
89*38fd1498Szrj   };
90*38fd1498Szrj 
91*38fd1498Szrj   class __concurrence_wait_error : public std::exception
92*38fd1498Szrj   {
93*38fd1498Szrj   public:
94*38fd1498Szrj     virtual char const*
95*38fd1498Szrj     what() const throw()
96*38fd1498Szrj     { return "__gnu_cxx::__concurrence_wait_error"; }
97*38fd1498Szrj   };
98*38fd1498Szrj 
99*38fd1498Szrj   // Substitute for concurrence_error object in the case of -fno-exceptions.
100*38fd1498Szrj   inline void
101*38fd1498Szrj   __throw_concurrence_lock_error()
102*38fd1498Szrj   { _GLIBCXX_THROW_OR_ABORT(__concurrence_lock_error()); }
103*38fd1498Szrj 
104*38fd1498Szrj   inline void
105*38fd1498Szrj   __throw_concurrence_unlock_error()
106*38fd1498Szrj   { _GLIBCXX_THROW_OR_ABORT(__concurrence_unlock_error()); }
107*38fd1498Szrj 
108*38fd1498Szrj #ifdef __GTHREAD_HAS_COND
109*38fd1498Szrj   inline void
110*38fd1498Szrj   __throw_concurrence_broadcast_error()
111*38fd1498Szrj   { _GLIBCXX_THROW_OR_ABORT(__concurrence_broadcast_error()); }
112*38fd1498Szrj 
113*38fd1498Szrj   inline void
114*38fd1498Szrj   __throw_concurrence_wait_error()
115*38fd1498Szrj   { _GLIBCXX_THROW_OR_ABORT(__concurrence_wait_error()); }
116*38fd1498Szrj #endif
117*38fd1498Szrj 
118*38fd1498Szrj   class __mutex
119*38fd1498Szrj   {
120*38fd1498Szrj   private:
121*38fd1498Szrj #if __GTHREADS && defined __GTHREAD_MUTEX_INIT
122*38fd1498Szrj     __gthread_mutex_t _M_mutex = __GTHREAD_MUTEX_INIT;
123*38fd1498Szrj #else
124*38fd1498Szrj     __gthread_mutex_t _M_mutex;
125*38fd1498Szrj #endif
126*38fd1498Szrj 
127*38fd1498Szrj     __mutex(const __mutex&);
128*38fd1498Szrj     __mutex& operator=(const __mutex&);
129*38fd1498Szrj 
130*38fd1498Szrj   public:
131*38fd1498Szrj     __mutex()
132*38fd1498Szrj     {
133*38fd1498Szrj #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT
134*38fd1498Szrj       if (__gthread_active_p())
135*38fd1498Szrj 	__GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
136*38fd1498Szrj #endif
137*38fd1498Szrj     }
138*38fd1498Szrj 
139*38fd1498Szrj #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT
140*38fd1498Szrj     ~__mutex()
141*38fd1498Szrj     {
142*38fd1498Szrj       if (__gthread_active_p())
143*38fd1498Szrj 	__gthread_mutex_destroy(&_M_mutex);
144*38fd1498Szrj     }
145*38fd1498Szrj #endif
146*38fd1498Szrj 
147*38fd1498Szrj     void lock()
148*38fd1498Szrj     {
149*38fd1498Szrj #if __GTHREADS
150*38fd1498Szrj       if (__gthread_active_p())
151*38fd1498Szrj 	{
152*38fd1498Szrj 	  if (__gthread_mutex_lock(&_M_mutex) != 0)
153*38fd1498Szrj 	    __throw_concurrence_lock_error();
154*38fd1498Szrj 	}
155*38fd1498Szrj #endif
156*38fd1498Szrj     }
157*38fd1498Szrj 
158*38fd1498Szrj     void unlock()
159*38fd1498Szrj     {
160*38fd1498Szrj #if __GTHREADS
161*38fd1498Szrj       if (__gthread_active_p())
162*38fd1498Szrj 	{
163*38fd1498Szrj 	  if (__gthread_mutex_unlock(&_M_mutex) != 0)
164*38fd1498Szrj 	    __throw_concurrence_unlock_error();
165*38fd1498Szrj 	}
166*38fd1498Szrj #endif
167*38fd1498Szrj     }
168*38fd1498Szrj 
169*38fd1498Szrj     __gthread_mutex_t* gthread_mutex(void)
170*38fd1498Szrj       { return &_M_mutex; }
171*38fd1498Szrj   };
172*38fd1498Szrj 
173*38fd1498Szrj   class __recursive_mutex
174*38fd1498Szrj   {
175*38fd1498Szrj   private:
176*38fd1498Szrj #if __GTHREADS && defined __GTHREAD_RECURSIVE_MUTEX_INIT
177*38fd1498Szrj     __gthread_recursive_mutex_t _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT;
178*38fd1498Szrj #else
179*38fd1498Szrj     __gthread_recursive_mutex_t _M_mutex;
180*38fd1498Szrj #endif
181*38fd1498Szrj 
182*38fd1498Szrj     __recursive_mutex(const __recursive_mutex&);
183*38fd1498Szrj     __recursive_mutex& operator=(const __recursive_mutex&);
184*38fd1498Szrj 
185*38fd1498Szrj   public:
186*38fd1498Szrj     __recursive_mutex()
187*38fd1498Szrj     {
188*38fd1498Szrj #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT
189*38fd1498Szrj       if (__gthread_active_p())
190*38fd1498Szrj 	__GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
191*38fd1498Szrj #endif
192*38fd1498Szrj     }
193*38fd1498Szrj 
194*38fd1498Szrj #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT
195*38fd1498Szrj     ~__recursive_mutex()
196*38fd1498Szrj     {
197*38fd1498Szrj       if (__gthread_active_p())
198*38fd1498Szrj 	__gthread_recursive_mutex_destroy(&_M_mutex);
199*38fd1498Szrj     }
200*38fd1498Szrj #endif
201*38fd1498Szrj 
202*38fd1498Szrj     void lock()
203*38fd1498Szrj     {
204*38fd1498Szrj #if __GTHREADS
205*38fd1498Szrj       if (__gthread_active_p())
206*38fd1498Szrj 	{
207*38fd1498Szrj 	  if (__gthread_recursive_mutex_lock(&_M_mutex) != 0)
208*38fd1498Szrj 	    __throw_concurrence_lock_error();
209*38fd1498Szrj 	}
210*38fd1498Szrj #endif
211*38fd1498Szrj     }
212*38fd1498Szrj 
213*38fd1498Szrj     void unlock()
214*38fd1498Szrj     {
215*38fd1498Szrj #if __GTHREADS
216*38fd1498Szrj       if (__gthread_active_p())
217*38fd1498Szrj 	{
218*38fd1498Szrj 	  if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0)
219*38fd1498Szrj 	    __throw_concurrence_unlock_error();
220*38fd1498Szrj 	}
221*38fd1498Szrj #endif
222*38fd1498Szrj     }
223*38fd1498Szrj 
224*38fd1498Szrj     __gthread_recursive_mutex_t* gthread_recursive_mutex(void)
225*38fd1498Szrj     { return &_M_mutex; }
226*38fd1498Szrj   };
227*38fd1498Szrj 
228*38fd1498Szrj   /// Scoped lock idiom.
229*38fd1498Szrj   // Acquire the mutex here with a constructor call, then release with
230*38fd1498Szrj   // the destructor call in accordance with RAII style.
231*38fd1498Szrj   class __scoped_lock
232*38fd1498Szrj   {
233*38fd1498Szrj   public:
234*38fd1498Szrj     typedef __mutex __mutex_type;
235*38fd1498Szrj 
236*38fd1498Szrj   private:
237*38fd1498Szrj     __mutex_type& _M_device;
238*38fd1498Szrj 
239*38fd1498Szrj     __scoped_lock(const __scoped_lock&);
240*38fd1498Szrj     __scoped_lock& operator=(const __scoped_lock&);
241*38fd1498Szrj 
242*38fd1498Szrj   public:
243*38fd1498Szrj     explicit __scoped_lock(__mutex_type& __name) : _M_device(__name)
244*38fd1498Szrj     { _M_device.lock(); }
245*38fd1498Szrj 
246*38fd1498Szrj     ~__scoped_lock() throw()
247*38fd1498Szrj     { _M_device.unlock(); }
248*38fd1498Szrj   };
249*38fd1498Szrj 
250*38fd1498Szrj #ifdef __GTHREAD_HAS_COND
251*38fd1498Szrj   class __cond
252*38fd1498Szrj   {
253*38fd1498Szrj   private:
254*38fd1498Szrj #if __GTHREADS && defined __GTHREAD_COND_INIT
255*38fd1498Szrj     __gthread_cond_t _M_cond = __GTHREAD_COND_INIT;
256*38fd1498Szrj #else
257*38fd1498Szrj     __gthread_cond_t _M_cond;
258*38fd1498Szrj #endif
259*38fd1498Szrj 
260*38fd1498Szrj     __cond(const __cond&);
261*38fd1498Szrj     __cond& operator=(const __cond&);
262*38fd1498Szrj 
263*38fd1498Szrj   public:
264*38fd1498Szrj     __cond()
265*38fd1498Szrj     {
266*38fd1498Szrj #if __GTHREADS && ! defined __GTHREAD_COND_INIT
267*38fd1498Szrj       if (__gthread_active_p())
268*38fd1498Szrj 	__GTHREAD_COND_INIT_FUNCTION(&_M_cond);
269*38fd1498Szrj #endif
270*38fd1498Szrj     }
271*38fd1498Szrj 
272*38fd1498Szrj #if __GTHREADS && ! defined __GTHREAD_COND_INIT
273*38fd1498Szrj     ~__cond()
274*38fd1498Szrj     {
275*38fd1498Szrj       if (__gthread_active_p())
276*38fd1498Szrj 	__gthread_cond_destroy(&_M_cond);
277*38fd1498Szrj     }
278*38fd1498Szrj #endif
279*38fd1498Szrj 
280*38fd1498Szrj     void broadcast()
281*38fd1498Szrj     {
282*38fd1498Szrj #if __GTHREADS
283*38fd1498Szrj       if (__gthread_active_p())
284*38fd1498Szrj 	{
285*38fd1498Szrj 	  if (__gthread_cond_broadcast(&_M_cond) != 0)
286*38fd1498Szrj 	    __throw_concurrence_broadcast_error();
287*38fd1498Szrj 	}
288*38fd1498Szrj #endif
289*38fd1498Szrj     }
290*38fd1498Szrj 
291*38fd1498Szrj     void wait(__mutex *mutex)
292*38fd1498Szrj     {
293*38fd1498Szrj #if __GTHREADS
294*38fd1498Szrj       {
295*38fd1498Szrj 	  if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0)
296*38fd1498Szrj 	    __throw_concurrence_wait_error();
297*38fd1498Szrj       }
298*38fd1498Szrj #endif
299*38fd1498Szrj     }
300*38fd1498Szrj 
301*38fd1498Szrj     void wait_recursive(__recursive_mutex *mutex)
302*38fd1498Szrj     {
303*38fd1498Szrj #if __GTHREADS
304*38fd1498Szrj       {
305*38fd1498Szrj 	  if (__gthread_cond_wait_recursive(&_M_cond,
306*38fd1498Szrj 					    mutex->gthread_recursive_mutex())
307*38fd1498Szrj 	      != 0)
308*38fd1498Szrj 	    __throw_concurrence_wait_error();
309*38fd1498Szrj       }
310*38fd1498Szrj #endif
311*38fd1498Szrj     }
312*38fd1498Szrj   };
313*38fd1498Szrj #endif
314*38fd1498Szrj 
315*38fd1498Szrj _GLIBCXX_END_NAMESPACE_VERSION
316*38fd1498Szrj } // namespace
317*38fd1498Szrj 
318*38fd1498Szrj #endif
319