1*404b540aSrobert // Support for concurrent programing -*- C++ -*-
2*404b540aSrobert 
3*404b540aSrobert // Copyright (C) 2003, 2004, 2005, 2006
4*404b540aSrobert // Free Software Foundation, Inc.
5*404b540aSrobert //
6*404b540aSrobert // This file is part of the GNU ISO C++ Library.  This library is free
7*404b540aSrobert // software; you can redistribute it and/or modify it under the
8*404b540aSrobert // terms of the GNU General Public License as published by the
9*404b540aSrobert // Free Software Foundation; either version 2, or (at your option)
10*404b540aSrobert // any later version.
11*404b540aSrobert 
12*404b540aSrobert // This library is distributed in the hope that it will be useful,
13*404b540aSrobert // but WITHOUT ANY WARRANTY; without even the implied warranty of
14*404b540aSrobert // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*404b540aSrobert // GNU General Public License for more details.
16*404b540aSrobert 
17*404b540aSrobert // You should have received a copy of the GNU General Public License along
18*404b540aSrobert // with this library; see the file COPYING.  If not, write to the Free
19*404b540aSrobert // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20*404b540aSrobert // USA.
21*404b540aSrobert 
22*404b540aSrobert // As a special exception, you may use this file as part of a free software
23*404b540aSrobert // library without restriction.  Specifically, if other files instantiate
24*404b540aSrobert // templates or use macros or inline functions from this file, or you compile
25*404b540aSrobert // this file and link it with other files to produce an executable, this
26*404b540aSrobert // file does not by itself cause the resulting executable to be covered by
27*404b540aSrobert // the GNU General Public License.  This exception does not however
28*404b540aSrobert // invalidate any other reasons why the executable file might be covered by
29*404b540aSrobert // the GNU General Public License.
30*404b540aSrobert 
31*404b540aSrobert /** @file concurrence.h
32*404b540aSrobert  *  This is an internal header file, included by other library headers.
33*404b540aSrobert  *  You should not attempt to use it directly.
34*404b540aSrobert  */
35*404b540aSrobert 
36*404b540aSrobert #ifndef _CONCURRENCE_H
37*404b540aSrobert #define _CONCURRENCE_H 1
38*404b540aSrobert 
39*404b540aSrobert #include <cstdlib>
40*404b540aSrobert #include <exception>
41*404b540aSrobert #include <bits/gthr.h>
42*404b540aSrobert #include <bits/functexcept.h>
43*404b540aSrobert 
44*404b540aSrobert _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
45*404b540aSrobert 
46*404b540aSrobert   // Available locking policies:
47*404b540aSrobert   // _S_single    single-threaded code that doesn't need to be locked.
48*404b540aSrobert   // _S_mutex     multi-threaded code that requires additional support
49*404b540aSrobert   //              from gthr.h or abstraction layers in concurrance.h.
50*404b540aSrobert   // _S_atomic    multi-threaded code using atomic operations.
51*404b540aSrobert   enum _Lock_policy { _S_single, _S_mutex, _S_atomic };
52*404b540aSrobert 
53*404b540aSrobert   // Compile time constant that indicates prefered locking policy in
54*404b540aSrobert   // the current configuration.
55*404b540aSrobert   static const _Lock_policy __default_lock_policy =
56*404b540aSrobert #ifdef __GTHREADS
57*404b540aSrobert   // NB: This macro doesn't actually exist yet in the compiler, but is
58*404b540aSrobert   // set somewhat haphazardly at configure time.
59*404b540aSrobert #ifdef _GLIBCXX_ATOMIC_BUILTINS
60*404b540aSrobert   _S_atomic;
61*404b540aSrobert #else
62*404b540aSrobert   _S_mutex;
63*404b540aSrobert #endif
64*404b540aSrobert #else
65*404b540aSrobert   _S_single;
66*404b540aSrobert #endif
67*404b540aSrobert 
68*404b540aSrobert   // NB: As this is used in libsupc++, need to only depend on
69*404b540aSrobert   // exception. No stdexception classes, no use of std::string.
70*404b540aSrobert   class __concurrence_lock_error : public std::exception
71*404b540aSrobert   {
72*404b540aSrobert   public:
73*404b540aSrobert     virtual char const*
what()74*404b540aSrobert     what() const throw()
75*404b540aSrobert     { return "__gnu_cxx::__concurrence_lock_error"; }
76*404b540aSrobert   };
77*404b540aSrobert 
78*404b540aSrobert   class __concurrence_unlock_error : public std::exception
79*404b540aSrobert   {
80*404b540aSrobert   public:
81*404b540aSrobert     virtual char const*
what()82*404b540aSrobert     what() const throw()
83*404b540aSrobert     { return "__gnu_cxx::__concurrence_unlock_error"; }
84*404b540aSrobert   };
85*404b540aSrobert 
86*404b540aSrobert   // Substitute for concurrence_error object in the case of -fno-exceptions.
87*404b540aSrobert   inline void
__throw_concurrence_lock_error()88*404b540aSrobert   __throw_concurrence_lock_error()
89*404b540aSrobert   {
90*404b540aSrobert #if __EXCEPTIONS
91*404b540aSrobert     throw __concurrence_lock_error();
92*404b540aSrobert #else
93*404b540aSrobert     std::abort();
94*404b540aSrobert #endif
95*404b540aSrobert   }
96*404b540aSrobert 
97*404b540aSrobert   inline void
__throw_concurrence_unlock_error()98*404b540aSrobert   __throw_concurrence_unlock_error()
99*404b540aSrobert   {
100*404b540aSrobert #if __EXCEPTIONS
101*404b540aSrobert     throw __concurrence_unlock_error();
102*404b540aSrobert #else
103*404b540aSrobert     std::abort();
104*404b540aSrobert #endif
105*404b540aSrobert   }
106*404b540aSrobert 
107*404b540aSrobert   class __mutex
108*404b540aSrobert   {
109*404b540aSrobert   private:
110*404b540aSrobert     __gthread_mutex_t _M_mutex;
111*404b540aSrobert 
112*404b540aSrobert     __mutex(const __mutex&);
113*404b540aSrobert     __mutex& operator=(const __mutex&);
114*404b540aSrobert 
115*404b540aSrobert   public:
__mutex()116*404b540aSrobert     __mutex()
117*404b540aSrobert     {
118*404b540aSrobert #if __GTHREADS
119*404b540aSrobert       if (__gthread_active_p())
120*404b540aSrobert 	{
121*404b540aSrobert #if defined __GTHREAD_MUTEX_INIT
122*404b540aSrobert 	  __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
123*404b540aSrobert 	  _M_mutex = __tmp;
124*404b540aSrobert #else
125*404b540aSrobert 	  __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
126*404b540aSrobert #endif
127*404b540aSrobert 	}
128*404b540aSrobert #endif
129*404b540aSrobert     }
130*404b540aSrobert 
lock()131*404b540aSrobert     void lock()
132*404b540aSrobert     {
133*404b540aSrobert #if __GTHREADS
134*404b540aSrobert       if (__gthread_active_p())
135*404b540aSrobert 	{
136*404b540aSrobert 	  if (__gthread_mutex_lock(&_M_mutex) != 0)
137*404b540aSrobert 	    __throw_concurrence_lock_error();
138*404b540aSrobert 	}
139*404b540aSrobert #endif
140*404b540aSrobert     }
141*404b540aSrobert 
unlock()142*404b540aSrobert     void unlock()
143*404b540aSrobert     {
144*404b540aSrobert #if __GTHREADS
145*404b540aSrobert       if (__gthread_active_p())
146*404b540aSrobert 	{
147*404b540aSrobert 	  if (__gthread_mutex_unlock(&_M_mutex) != 0)
148*404b540aSrobert 	    __throw_concurrence_unlock_error();
149*404b540aSrobert 	}
150*404b540aSrobert #endif
151*404b540aSrobert     }
152*404b540aSrobert   };
153*404b540aSrobert 
154*404b540aSrobert   class __recursive_mutex
155*404b540aSrobert   {
156*404b540aSrobert   private:
157*404b540aSrobert     __gthread_recursive_mutex_t _M_mutex;
158*404b540aSrobert 
159*404b540aSrobert     __recursive_mutex(const __recursive_mutex&);
160*404b540aSrobert     __recursive_mutex& operator=(const __recursive_mutex&);
161*404b540aSrobert 
162*404b540aSrobert   public:
__recursive_mutex()163*404b540aSrobert     __recursive_mutex()
164*404b540aSrobert     {
165*404b540aSrobert #if __GTHREADS
166*404b540aSrobert       if (__gthread_active_p())
167*404b540aSrobert 	{
168*404b540aSrobert #if defined __GTHREAD_RECURSIVE_MUTEX_INIT
169*404b540aSrobert 	  __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT;
170*404b540aSrobert 	  _M_mutex = __tmp;
171*404b540aSrobert #else
172*404b540aSrobert 	  __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
173*404b540aSrobert #endif
174*404b540aSrobert 	}
175*404b540aSrobert #endif
176*404b540aSrobert     }
177*404b540aSrobert 
lock()178*404b540aSrobert     void lock()
179*404b540aSrobert     {
180*404b540aSrobert #if __GTHREADS
181*404b540aSrobert       if (__gthread_active_p())
182*404b540aSrobert 	{
183*404b540aSrobert 	  if (__gthread_recursive_mutex_lock(&_M_mutex) != 0)
184*404b540aSrobert 	    __throw_concurrence_lock_error();
185*404b540aSrobert 	}
186*404b540aSrobert #endif
187*404b540aSrobert     }
188*404b540aSrobert 
unlock()189*404b540aSrobert     void unlock()
190*404b540aSrobert     {
191*404b540aSrobert #if __GTHREADS
192*404b540aSrobert       if (__gthread_active_p())
193*404b540aSrobert 	{
194*404b540aSrobert 	  if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0)
195*404b540aSrobert 	    __throw_concurrence_unlock_error();
196*404b540aSrobert 	}
197*404b540aSrobert #endif
198*404b540aSrobert     }
199*404b540aSrobert   };
200*404b540aSrobert 
201*404b540aSrobert   /// @brief  Scoped lock idiom.
202*404b540aSrobert   // Acquire the mutex here with a constructor call, then release with
203*404b540aSrobert   // the destructor call in accordance with RAII style.
204*404b540aSrobert   class __scoped_lock
205*404b540aSrobert   {
206*404b540aSrobert   public:
207*404b540aSrobert     typedef __mutex __mutex_type;
208*404b540aSrobert 
209*404b540aSrobert   private:
210*404b540aSrobert     __mutex_type& _M_device;
211*404b540aSrobert 
212*404b540aSrobert     __scoped_lock(const __scoped_lock&);
213*404b540aSrobert     __scoped_lock& operator=(const __scoped_lock&);
214*404b540aSrobert 
215*404b540aSrobert   public:
__scoped_lock(__mutex_type & __name)216*404b540aSrobert     explicit __scoped_lock(__mutex_type& __name) : _M_device(__name)
217*404b540aSrobert     { _M_device.lock(); }
218*404b540aSrobert 
throw()219*404b540aSrobert     ~__scoped_lock() throw()
220*404b540aSrobert     { _M_device.unlock(); }
221*404b540aSrobert   };
222*404b540aSrobert 
223*404b540aSrobert _GLIBCXX_END_NAMESPACE
224*404b540aSrobert 
225*404b540aSrobert #endif
226