concurrence.h

Go to the documentation of this file.
00001 // Support for concurrent programing -*- C++ -*-
00002 
00003 // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
00004 // Free Software Foundation, Inc.
00005 //
00006 // This file is part of the GNU ISO C++ Library.  This library is free
00007 // software; you can redistribute it and/or modify it under the
00008 // terms of the GNU General Public License as published by the
00009 // Free Software Foundation; either version 3, or (at your option)
00010 // any later version.
00011 
00012 // This library is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 
00017 // Under Section 7 of GPL version 3, you are granted additional
00018 // permissions described in the GCC Runtime Library Exception, version
00019 // 3.1, as published by the Free Software Foundation.
00020 
00021 // You should have received a copy of the GNU General Public License and
00022 // a copy of the GCC Runtime Library Exception along with this program;
00023 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
00024 // <http://www.gnu.org/licenses/>.
00025 
00026 /** @file concurrence.h
00027  *  This is an internal header file, included by other library headers.
00028  *  You should not attempt to use it directly.
00029  */
00030 
00031 #ifndef _CONCURRENCE_H
00032 #define _CONCURRENCE_H 1
00033 
00034 #pragma GCC system_header
00035 
00036 #include <exception>
00037 #include <bits/gthr.h> 
00038 #include <bits/functexcept.h>
00039 
00040 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
00041 
00042   // Available locking policies:
00043   // _S_single    single-threaded code that doesn't need to be locked.
00044   // _S_mutex     multi-threaded code that requires additional support
00045   //              from gthr.h or abstraction layers in concurrence.h.
00046   // _S_atomic    multi-threaded code using atomic operations.
00047   enum _Lock_policy { _S_single, _S_mutex, _S_atomic }; 
00048 
00049   // Compile time constant that indicates prefered locking policy in
00050   // the current configuration.
00051   static const _Lock_policy __default_lock_policy = 
00052 #ifdef __GTHREADS
00053 #if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) \
00054      && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4))
00055   _S_atomic;
00056 #else
00057   _S_mutex;
00058 #endif
00059 #else
00060   _S_single;
00061 #endif
00062 
00063   // NB: As this is used in libsupc++, need to only depend on
00064   // exception. No stdexception classes, no use of std::string.
00065   class __concurrence_lock_error : public std::exception
00066   {
00067   public:
00068     virtual char const*
00069     what() const throw()
00070     { return "__gnu_cxx::__concurrence_lock_error"; }
00071   };
00072 
00073   class __concurrence_unlock_error : public std::exception
00074   {
00075   public:
00076     virtual char const*
00077     what() const throw()
00078     { return "__gnu_cxx::__concurrence_unlock_error"; }
00079   };
00080 
00081   class __concurrence_broadcast_error : public std::exception
00082   {
00083   public:
00084     virtual char const*
00085     what() const throw()
00086     { return "__gnu_cxx::__concurrence_broadcast_error"; }
00087   };
00088 
00089   class __concurrence_wait_error : public std::exception
00090   {
00091   public:
00092     virtual char const*
00093     what() const throw()
00094     { return "__gnu_cxx::__concurrence_wait_error"; }
00095   };
00096 
00097   // Substitute for concurrence_error object in the case of -fno-exceptions.
00098   inline void
00099   __throw_concurrence_lock_error()
00100   {
00101 #if __EXCEPTIONS
00102     throw __concurrence_lock_error();
00103 #else
00104     __builtin_abort();
00105 #endif
00106   }
00107 
00108   inline void
00109   __throw_concurrence_unlock_error()
00110   {
00111 #if __EXCEPTIONS
00112     throw __concurrence_unlock_error();
00113 #else
00114     __builtin_abort();
00115 #endif
00116   }
00117 
00118 #ifdef __GTHREAD_HAS_COND
00119   inline void
00120   __throw_concurrence_broadcast_error()
00121   {
00122 #if __EXCEPTIONS
00123     throw __concurrence_broadcast_error();
00124 #else
00125     __builtin_abort();
00126 #endif
00127   }
00128 
00129   inline void
00130   __throw_concurrence_wait_error()
00131   {
00132 #if __EXCEPTIONS
00133     throw __concurrence_wait_error();
00134 #else
00135     __builtin_abort();
00136 #endif
00137   }
00138 #endif
00139  
00140   class __mutex 
00141   {
00142   private:
00143     __gthread_mutex_t _M_mutex;
00144 
00145     __mutex(const __mutex&);
00146     __mutex& operator=(const __mutex&);
00147 
00148   public:
00149     __mutex() 
00150     { 
00151 #if __GTHREADS
00152       if (__gthread_active_p())
00153     {
00154 #if defined __GTHREAD_MUTEX_INIT
00155       __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
00156       _M_mutex = __tmp;
00157 #else
00158       __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); 
00159 #endif
00160     }
00161 #endif 
00162     }
00163 
00164     void lock()
00165     {
00166 #if __GTHREADS
00167       if (__gthread_active_p())
00168     {
00169       if (__gthread_mutex_lock(&_M_mutex) != 0)
00170         __throw_concurrence_lock_error();
00171     }
00172 #endif
00173     }
00174     
00175     void unlock()
00176     {
00177 #if __GTHREADS
00178       if (__gthread_active_p())
00179     {
00180       if (__gthread_mutex_unlock(&_M_mutex) != 0)
00181         __throw_concurrence_unlock_error();
00182     }
00183 #endif
00184     }
00185 
00186     __gthread_mutex_t* gthread_mutex(void)
00187       { return &_M_mutex; }
00188   };
00189 
00190   class __recursive_mutex 
00191   {
00192   private:
00193     __gthread_recursive_mutex_t _M_mutex;
00194 
00195     __recursive_mutex(const __recursive_mutex&);
00196     __recursive_mutex& operator=(const __recursive_mutex&);
00197 
00198   public:
00199     __recursive_mutex() 
00200     { 
00201 #if __GTHREADS
00202       if (__gthread_active_p())
00203     {
00204 #if defined __GTHREAD_RECURSIVE_MUTEX_INIT
00205       __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT;
00206       _M_mutex = __tmp;
00207 #else
00208       __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); 
00209 #endif
00210     }
00211 #endif 
00212     }
00213 
00214     void lock()
00215     { 
00216 #if __GTHREADS
00217       if (__gthread_active_p())
00218     {
00219       if (__gthread_recursive_mutex_lock(&_M_mutex) != 0)
00220         __throw_concurrence_lock_error();
00221     }
00222 #endif
00223     }
00224     
00225     void unlock()
00226     { 
00227 #if __GTHREADS
00228       if (__gthread_active_p())
00229     {
00230       if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0)
00231         __throw_concurrence_unlock_error();
00232     }
00233 #endif
00234     }
00235 
00236     __gthread_recursive_mutex_t* gthread_recursive_mutex(void)
00237       { return &_M_mutex; }
00238   };
00239 
00240   /// Scoped lock idiom.
00241   // Acquire the mutex here with a constructor call, then release with
00242   // the destructor call in accordance with RAII style.
00243   class __scoped_lock
00244   {
00245   public:
00246     typedef __mutex __mutex_type;
00247 
00248   private:
00249     __mutex_type& _M_device;
00250 
00251     __scoped_lock(const __scoped_lock&);
00252     __scoped_lock& operator=(const __scoped_lock&);
00253 
00254   public:
00255     explicit __scoped_lock(__mutex_type& __name) : _M_device(__name)
00256     { _M_device.lock(); }
00257 
00258     ~__scoped_lock() throw()
00259     { _M_device.unlock(); }
00260   };
00261 
00262 #ifdef __GTHREAD_HAS_COND
00263   class __cond
00264   {
00265   private:
00266     __gthread_cond_t _M_cond;
00267 
00268     __cond(const __cond&);
00269     __cond& operator=(const __cond&);
00270 
00271   public:
00272     __cond() 
00273     { 
00274 #if __GTHREADS
00275       if (__gthread_active_p())
00276     {
00277 #if defined __GTHREAD_COND_INIT
00278       __gthread_cond_t __tmp = __GTHREAD_COND_INIT;
00279       _M_cond = __tmp;
00280 #else
00281       __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
00282 #endif
00283     }
00284 #endif 
00285     }
00286 
00287     void broadcast()
00288     {
00289 #if __GTHREADS
00290       if (__gthread_active_p())
00291     {
00292       if (__gthread_cond_broadcast(&_M_cond) != 0)
00293         __throw_concurrence_broadcast_error();
00294     }
00295 #endif
00296     }
00297 
00298     void wait(__mutex *mutex)
00299     {
00300 #if __GTHREADS
00301       {
00302       if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0)
00303         __throw_concurrence_wait_error();
00304       }
00305 #endif
00306     }
00307 
00308     void wait_recursive(__recursive_mutex *mutex)
00309     {
00310 #if __GTHREADS
00311       {
00312       if (__gthread_cond_wait_recursive(&_M_cond,
00313                         mutex->gthread_recursive_mutex())
00314           != 0)
00315         __throw_concurrence_wait_error();
00316       }
00317 #endif
00318     }
00319   };
00320 #endif
00321 
00322 _GLIBCXX_END_NAMESPACE
00323 
00324 #endif