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