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