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, 2012
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 #if __GTHREADS && defined __GTHREAD_MUTEX_INIT
00147     __gthread_mutex_t _M_mutex = __GTHREAD_MUTEX_INIT;
00148 #else
00149     __gthread_mutex_t _M_mutex;
00150 #endif
00151 
00152     __mutex(const __mutex&);
00153     __mutex& operator=(const __mutex&);
00154 
00155   public:
00156     __mutex() 
00157     { 
00158 #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT
00159       if (__gthread_active_p())
00160     __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
00161 #endif
00162     }
00163 
00164 #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT
00165     ~__mutex() 
00166     { 
00167       if (__gthread_active_p())
00168     __gthread_mutex_destroy(&_M_mutex); 
00169     }
00170 #endif 
00171 
00172     void lock()
00173     {
00174 #if __GTHREADS
00175       if (__gthread_active_p())
00176     {
00177       if (__gthread_mutex_lock(&_M_mutex) != 0)
00178         __throw_concurrence_lock_error();
00179     }
00180 #endif
00181     }
00182     
00183     void unlock()
00184     {
00185 #if __GTHREADS
00186       if (__gthread_active_p())
00187     {
00188       if (__gthread_mutex_unlock(&_M_mutex) != 0)
00189         __throw_concurrence_unlock_error();
00190     }
00191 #endif
00192     }
00193 
00194     __gthread_mutex_t* gthread_mutex(void)
00195       { return &_M_mutex; }
00196   };
00197 
00198   class __recursive_mutex 
00199   {
00200   private:
00201 #if __GTHREADS && defined __GTHREAD_RECURSIVE_MUTEX_INIT
00202     __gthread_recursive_mutex_t _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT;
00203 #else
00204     __gthread_recursive_mutex_t _M_mutex;
00205 #endif
00206 
00207     __recursive_mutex(const __recursive_mutex&);
00208     __recursive_mutex& operator=(const __recursive_mutex&);
00209 
00210   public:
00211     __recursive_mutex() 
00212     { 
00213 #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT
00214       if (__gthread_active_p())
00215     __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
00216 #endif
00217     }
00218 
00219 #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT
00220     ~__recursive_mutex()
00221     {
00222       if (__gthread_active_p())
00223     _S_destroy(&_M_mutex);
00224     }
00225 #endif
00226 
00227     void lock()
00228     { 
00229 #if __GTHREADS
00230       if (__gthread_active_p())
00231     {
00232       if (__gthread_recursive_mutex_lock(&_M_mutex) != 0)
00233         __throw_concurrence_lock_error();
00234     }
00235 #endif
00236     }
00237     
00238     void unlock()
00239     { 
00240 #if __GTHREADS
00241       if (__gthread_active_p())
00242     {
00243       if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0)
00244         __throw_concurrence_unlock_error();
00245     }
00246 #endif
00247     }
00248 
00249     __gthread_recursive_mutex_t* gthread_recursive_mutex(void)
00250     { return &_M_mutex; }
00251 
00252 #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT
00253     // FIXME: gthreads doesn't define __gthread_recursive_mutex_destroy
00254     // so we need to obtain a __gthread_mutex_t to destroy
00255   private:
00256     template<typename _Mx, typename _Rm>
00257       static void
00258       _S_destroy_win32(_Mx* __mx, _Rm const* __rmx)
00259       {
00260         __mx->counter = __rmx->counter;
00261         __mx->sema = __rmx->sema;
00262         __gthread_mutex_destroy(__mx);
00263       }
00264 
00265     // matches a gthr-win32.h recursive mutex
00266     template<typename _Rm>
00267       static typename __enable_if<(bool)sizeof(&_Rm::sema), void>::__type
00268       _S_destroy(_Rm* __mx)
00269       {
00270         __gthread_mutex_t __tmp;
00271         _S_destroy_win32(&__tmp, __mx);
00272       }
00273 
00274     // matches a recursive mutex with a member 'actual'
00275     template<typename _Rm>
00276       static typename __enable_if<(bool)sizeof(&_Rm::actual), void>::__type
00277       _S_destroy(_Rm* __mx)
00278       { __gthread_mutex_destroy(&__mx->actual); }
00279 
00280     // matches when there's only one mutex type
00281     template<typename _Rm>
00282       static typename
00283       __enable_if<std::__are_same<_Rm, __gthread_mutex_t>::__value,
00284         void>::__type
00285       _S_destroy(_Rm* __mx)
00286       { __gthread_mutex_destroy(__mx); }
00287 #endif
00288   };
00289 
00290   /// Scoped lock idiom.
00291   // Acquire the mutex here with a constructor call, then release with
00292   // the destructor call in accordance with RAII style.
00293   class __scoped_lock
00294   {
00295   public:
00296     typedef __mutex __mutex_type;
00297 
00298   private:
00299     __mutex_type& _M_device;
00300 
00301     __scoped_lock(const __scoped_lock&);
00302     __scoped_lock& operator=(const __scoped_lock&);
00303 
00304   public:
00305     explicit __scoped_lock(__mutex_type& __name) : _M_device(__name)
00306     { _M_device.lock(); }
00307 
00308     ~__scoped_lock() throw()
00309     { _M_device.unlock(); }
00310   };
00311 
00312 #ifdef __GTHREAD_HAS_COND
00313   class __cond
00314   {
00315   private:
00316 #if __GTHREADS && defined __GTHREAD_COND_INIT
00317     __gthread_cond_t _M_cond = __GTHREAD_COND_INIT;
00318 #else
00319     __gthread_cond_t _M_cond;
00320 #endif
00321 
00322     __cond(const __cond&);
00323     __cond& operator=(const __cond&);
00324 
00325   public:
00326     __cond() 
00327     { 
00328 #if __GTHREADS && ! defined __GTHREAD_COND_INIT
00329       if (__gthread_active_p())
00330     __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
00331 #endif
00332     }
00333 
00334 #if __GTHREADS && ! defined __GTHREAD_COND_INIT
00335     ~__cond() 
00336     { 
00337       if (__gthread_active_p())
00338     __gthread_cond_destroy(&_M_cond); 
00339     }
00340 #endif 
00341 
00342     void broadcast()
00343     {
00344 #if __GTHREADS
00345       if (__gthread_active_p())
00346     {
00347       if (__gthread_cond_broadcast(&_M_cond) != 0)
00348         __throw_concurrence_broadcast_error();
00349     }
00350 #endif
00351     }
00352 
00353     void wait(__mutex *mutex)
00354     {
00355 #if __GTHREADS
00356       {
00357       if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0)
00358         __throw_concurrence_wait_error();
00359       }
00360 #endif
00361     }
00362 
00363     void wait_recursive(__recursive_mutex *mutex)
00364     {
00365 #if __GTHREADS
00366       {
00367       if (__gthread_cond_wait_recursive(&_M_cond,
00368                         mutex->gthread_recursive_mutex())
00369           != 0)
00370         __throw_concurrence_wait_error();
00371       }
00372 #endif
00373     }
00374   };
00375 #endif
00376 
00377 _GLIBCXX_END_NAMESPACE_VERSION
00378 } // namespace
00379 
00380 #endif