libstdc++
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 ext/concurrence.h
00027  *  This file is a GNU extension to the Standard C++ Library.
00028  */
00029 
00030 #ifndef _CONCURRENCE_H
00031 #define _CONCURRENCE_H 1
00032 
00033 #pragma GCC system_header
00034 
00035 #include <exception>
00036 #include <bits/gthr.h> 
00037 #include <bits/functexcept.h>
00038 #include <bits/cpp_type_traits.h>
00039 #include <ext/type_traits.h>
00040 
00041 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
00042 {
00043 _GLIBCXX_BEGIN_NAMESPACE_VERSION
00044 
00045   // Available locking policies:
00046   // _S_single    single-threaded code that doesn't need to be locked.
00047   // _S_mutex     multi-threaded code that requires additional support
00048   //              from gthr.h or abstraction layers in concurrence.h.
00049   // _S_atomic    multi-threaded code using atomic operations.
00050   enum _Lock_policy { _S_single, _S_mutex, _S_atomic }; 
00051 
00052   // Compile time constant that indicates prefered locking policy in
00053   // the current configuration.
00054   static const _Lock_policy __default_lock_policy = 
00055 #ifdef __GTHREADS
00056 #if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) \
00057      && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4))
00058   _S_atomic;
00059 #else
00060   _S_mutex;
00061 #endif
00062 #else
00063   _S_single;
00064 #endif
00065 
00066   // NB: As this is used in libsupc++, need to only depend on
00067   // exception. No stdexception classes, no use of std::string.
00068   class __concurrence_lock_error : public std::exception
00069   {
00070   public:
00071     virtual char const*
00072     what() const throw()
00073     { return "__gnu_cxx::__concurrence_lock_error"; }
00074   };
00075 
00076   class __concurrence_unlock_error : public std::exception
00077   {
00078   public:
00079     virtual char const*
00080     what() const throw()
00081     { return "__gnu_cxx::__concurrence_unlock_error"; }
00082   };
00083 
00084   class __concurrence_broadcast_error : public std::exception
00085   {
00086   public:
00087     virtual char const*
00088     what() const throw()
00089     { return "__gnu_cxx::__concurrence_broadcast_error"; }
00090   };
00091 
00092   class __concurrence_wait_error : public std::exception
00093   {
00094   public:
00095     virtual char const*
00096     what() const throw()
00097     { return "__gnu_cxx::__concurrence_wait_error"; }
00098   };
00099 
00100   // Substitute for concurrence_error object in the case of -fno-exceptions.
00101   inline void
00102   __throw_concurrence_lock_error()
00103   {
00104 #if __EXCEPTIONS
00105     throw __concurrence_lock_error();
00106 #else
00107     __builtin_abort();
00108 #endif
00109   }
00110 
00111   inline void
00112   __throw_concurrence_unlock_error()
00113   {
00114 #if __EXCEPTIONS
00115     throw __concurrence_unlock_error();
00116 #else
00117     __builtin_abort();
00118 #endif
00119   }
00120 
00121 #ifdef __GTHREAD_HAS_COND
00122   inline void
00123   __throw_concurrence_broadcast_error()
00124   {
00125 #if __EXCEPTIONS
00126     throw __concurrence_broadcast_error();
00127 #else
00128     __builtin_abort();
00129 #endif
00130   }
00131 
00132   inline void
00133   __throw_concurrence_wait_error()
00134   {
00135 #if __EXCEPTIONS
00136     throw __concurrence_wait_error();
00137 #else
00138     __builtin_abort();
00139 #endif
00140   }
00141 #endif
00142  
00143   class __mutex 
00144   {
00145   private:
00146     __gthread_mutex_t _M_mutex;
00147 
00148     __mutex(const __mutex&);
00149     __mutex& operator=(const __mutex&);
00150 
00151   public:
00152     __mutex() 
00153     { 
00154 #if __GTHREADS
00155       if (__gthread_active_p())
00156     {
00157 #if defined __GTHREAD_MUTEX_INIT
00158       __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
00159       _M_mutex = __tmp;
00160 #else
00161       __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); 
00162 #endif
00163     }
00164 #endif 
00165     }
00166 
00167 #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT
00168     ~__mutex() 
00169     { 
00170       if (__gthread_active_p())
00171     __gthread_mutex_destroy(&_M_mutex); 
00172     }
00173 #endif 
00174 
00175     void lock()
00176     {
00177 #if __GTHREADS
00178       if (__gthread_active_p())
00179     {
00180       if (__gthread_mutex_lock(&_M_mutex) != 0)
00181         __throw_concurrence_lock_error();
00182     }
00183 #endif
00184     }
00185     
00186     void unlock()
00187     {
00188 #if __GTHREADS
00189       if (__gthread_active_p())
00190     {
00191       if (__gthread_mutex_unlock(&_M_mutex) != 0)
00192         __throw_concurrence_unlock_error();
00193     }
00194 #endif
00195     }
00196 
00197     __gthread_mutex_t* gthread_mutex(void)
00198       { return &_M_mutex; }
00199   };
00200 
00201   class __recursive_mutex 
00202   {
00203   private:
00204     __gthread_recursive_mutex_t _M_mutex;
00205 
00206     __recursive_mutex(const __recursive_mutex&);
00207     __recursive_mutex& operator=(const __recursive_mutex&);
00208 
00209   public:
00210     __recursive_mutex() 
00211     { 
00212 #if __GTHREADS
00213       if (__gthread_active_p())
00214     {
00215 #if defined __GTHREAD_RECURSIVE_MUTEX_INIT
00216       __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT;
00217       _M_mutex = __tmp;
00218 #else
00219       __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); 
00220 #endif
00221     }
00222 #endif 
00223     }
00224 
00225 #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT
00226     ~__recursive_mutex()
00227     {
00228       if (__gthread_active_p())
00229     _S_destroy(&_M_mutex);
00230     }
00231 #endif
00232 
00233     void lock()
00234     { 
00235 #if __GTHREADS
00236       if (__gthread_active_p())
00237     {
00238       if (__gthread_recursive_mutex_lock(&_M_mutex) != 0)
00239         __throw_concurrence_lock_error();
00240     }
00241 #endif
00242     }
00243     
00244     void unlock()
00245     { 
00246 #if __GTHREADS
00247       if (__gthread_active_p())
00248     {
00249       if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0)
00250         __throw_concurrence_unlock_error();
00251     }
00252 #endif
00253     }
00254 
00255     __gthread_recursive_mutex_t* gthread_recursive_mutex(void)
00256     { return &_M_mutex; }
00257 
00258 #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT
00259     // FIXME: gthreads doesn't define __gthread_recursive_mutex_destroy
00260     // so we need to obtain a __gthread_mutex_t to destroy
00261   private:
00262     template<typename _Mx, typename _Rm>
00263       static void
00264       _S_destroy_win32(_Mx* __mx, _Rm const* __rmx)
00265       {
00266         __mx->counter = __rmx->counter;
00267         __mx->sema = __rmx->sema;
00268         __gthread_mutex_destroy(__mx);
00269       }
00270 
00271     // matches a gthr-win32.h recursive mutex
00272     template<typename _Rm>
00273       static typename __enable_if<sizeof(&_Rm::sema), void>::__type
00274       _S_destroy(_Rm* __mx)
00275       {
00276         __gthread_mutex_t __tmp;
00277         _S_destroy_win32(&__tmp, __mx);
00278       }
00279 
00280     // matches a recursive mutex with a member 'actual'
00281     template<typename _Rm>
00282       static typename __enable_if<sizeof(&_Rm::actual), void>::__type
00283       _S_destroy(_Rm* __mx)
00284       { __gthread_mutex_destroy(&__mx->actual); }
00285 
00286     // matches when there's only one mutex type
00287     template<typename _Rm>
00288       static typename
00289       __enable_if<std::__are_same<_Rm, __gthread_mutex_t>::__value,
00290         void>::__type
00291       _S_destroy(_Rm* __mx)
00292       { __gthread_mutex_destroy(__mx); }
00293 #endif
00294   };
00295 
00296   /// Scoped lock idiom.
00297   // Acquire the mutex here with a constructor call, then release with
00298   // the destructor call in accordance with RAII style.
00299   class __scoped_lock
00300   {
00301   public:
00302     typedef __mutex __mutex_type;
00303 
00304   private:
00305     __mutex_type& _M_device;
00306 
00307     __scoped_lock(const __scoped_lock&);
00308     __scoped_lock& operator=(const __scoped_lock&);
00309 
00310   public:
00311     explicit __scoped_lock(__mutex_type& __name) : _M_device(__name)
00312     { _M_device.lock(); }
00313 
00314     ~__scoped_lock() throw()
00315     { _M_device.unlock(); }
00316   };
00317 
00318 #ifdef __GTHREAD_HAS_COND
00319   class __cond
00320   {
00321   private:
00322     __gthread_cond_t _M_cond;
00323 
00324     __cond(const __cond&);
00325     __cond& operator=(const __cond&);
00326 
00327   public:
00328     __cond() 
00329     { 
00330 #if __GTHREADS
00331       if (__gthread_active_p())
00332     {
00333 #if defined __GTHREAD_COND_INIT
00334       __gthread_cond_t __tmp = __GTHREAD_COND_INIT;
00335       _M_cond = __tmp;
00336 #else
00337       __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
00338 #endif
00339     }
00340 #endif 
00341     }
00342 
00343 #if __GTHREADS && ! defined __GTHREAD_COND_INIT
00344     ~__cond() 
00345     { 
00346       if (__gthread_active_p())
00347     __gthread_cond_destroy(&_M_cond); 
00348     }
00349 #endif 
00350 
00351     void broadcast()
00352     {
00353 #if __GTHREADS
00354       if (__gthread_active_p())
00355     {
00356       if (__gthread_cond_broadcast(&_M_cond) != 0)
00357         __throw_concurrence_broadcast_error();
00358     }
00359 #endif
00360     }
00361 
00362     void wait(__mutex *mutex)
00363     {
00364 #if __GTHREADS
00365       {
00366       if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0)
00367         __throw_concurrence_wait_error();
00368       }
00369 #endif
00370     }
00371 
00372     void wait_recursive(__recursive_mutex *mutex)
00373     {
00374 #if __GTHREADS
00375       {
00376       if (__gthread_cond_wait_recursive(&_M_cond,
00377                         mutex->gthread_recursive_mutex())
00378           != 0)
00379         __throw_concurrence_wait_error();
00380       }
00381 #endif
00382     }
00383   };
00384 #endif
00385 
00386 _GLIBCXX_END_NAMESPACE_VERSION
00387 } // namespace
00388 
00389 #endif