# concurrence.h

Go to the documentation of this file.

    00001 // Support for concurrent programing -*- C++ -*-
    00002
    00003 // Copyright (C) 2003, 2004, 2005, 2006, 2007
    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 2, 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 // You should have received a copy of the GNU General Public License along
    00018 // with this library; see the file COPYING.  If not, write to the Free
    00019 // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
    00020 // USA.
    00021
    00022 // As a special exception, you may use this file as part of a free software
    00023 // library without restriction.  Specifically, if other files instantiate
    00024 // templates or use macros or inline functions from this file, or you compile
    00025 // this file and link it with other files to produce an executable, this
    00026 // file does not by itself cause the resulting executable to be covered by
    00027 // the GNU General Public License.  This exception does not however
    00028 // invalidate any other reasons why the executable file might be covered by
    00029 // the GNU General Public License.
    00030
    00031 /** @file concurrence.h
    00032  *  This is an internal header file, included by other library headers.
    00033  *  You should not attempt to use it directly.
    00034  */
    00035
    00036 #ifndef _CONCURRENCE_H
    00037 #define _CONCURRENCE_H 1
    00038
    00039 #include <exception>
    00040 #include <bits/gthr.h>
    00041 #include <bits/functexcept.h>
    00042
    00043 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
    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     void lock()
    00168     {
    00169 #if __GTHREADS
    00170       if (__gthread_active_p())
    00171     {
    00172       if (__gthread_mutex_lock(&_M_mutex) != 0)
    00173         __throw_concurrence_lock_error();
    00174     }
    00175 #endif
    00176     }
    00177
    00178     void unlock()
    00179     {
    00180 #if __GTHREADS
    00181       if (__gthread_active_p())
    00182     {
    00183       if (__gthread_mutex_unlock(&_M_mutex) != 0)
    00184         __throw_concurrence_unlock_error();
    00185     }
    00186 #endif
    00187     }
    00188
    00189     __gthread_mutex_t* gthread_mutex(void)
    00190       { return &_M_mutex; }
    00191   };
    00192
    00193   class __recursive_mutex
    00194   {
    00195   private:
    00196     __gthread_recursive_mutex_t _M_mutex;
    00197
    00198     __recursive_mutex(const __recursive_mutex&);
    00199     __recursive_mutex& operator=(const __recursive_mutex&);
    00200
    00201   public:
    00202     __recursive_mutex()
    00203     {
    00204 #if __GTHREADS
    00205       if (__gthread_active_p())
    00206     {
    00207 #if defined __GTHREAD_RECURSIVE_MUTEX_INIT
    00208       __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT;
    00209       _M_mutex = __tmp;
    00210 #else
    00211       __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
    00212 #endif
    00213     }
    00214 #endif
    00215     }
    00216
    00217     void lock()
    00218     {
    00219 #if __GTHREADS
    00220       if (__gthread_active_p())
    00221     {
    00222       if (__gthread_recursive_mutex_lock(&_M_mutex) != 0)
    00223         __throw_concurrence_lock_error();
    00224     }
    00225 #endif
    00226     }
    00227
    00228     void unlock()
    00229     {
    00230 #if __GTHREADS
    00231       if (__gthread_active_p())
    00232     {
    00233       if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0)
    00234         __throw_concurrence_unlock_error();
    00235     }
    00236 #endif
    00237     }
    00238
    00239     __gthread_recursive_mutex_t* gthread_recursive_mutex(void)
    00240       { return &_M_mutex; }
    00241   };
    00242
    00243   /// Scoped lock idiom.
    00244   // Acquire the mutex here with a constructor call, then release with
    00245   // the destructor call in accordance with RAII style.
    00246   class __scoped_lock
    00247   {
    00248   public:
    00249     typedef __mutex __mutex_type;
    00250
    00251   private:
    00252     __mutex_type& _M_device;
    00253
    00254     __scoped_lock(const __scoped_lock&);
    00255     __scoped_lock& operator=(const __scoped_lock&);
    00256
    00257   public:
    00258     explicit __scoped_lock(__mutex_type& __name) : _M_device(__name)
    00259     { _M_device.lock(); }
    00260
    00261     ~__scoped_lock() throw()
    00262     { _M_device.unlock(); }
    00263   };
    00264
    00265 #ifdef __GTHREAD_HAS_COND
    00266   class __cond
    00267   {
    00268   private:
    00269     __gthread_cond_t _M_cond;
    00270
    00271     __cond(const __cond&);
    00272     __cond& operator=(const __cond&);
    00273
    00274   public:
    00275     __cond()
    00276     {
    00277 #if __GTHREADS
    00278       if (__gthread_active_p())
    00279     {
    00280 #if defined __GTHREAD_COND_INIT
    00281       __gthread_cond_t __tmp = __GTHREAD_COND_INIT;
    00282       _M_cond = __tmp;
    00283 #else
    00284       __GTHREAD_MUTEX_INIT_FUNCTION(&_M_cond);
    00285 #endif
    00286     }
    00287 #endif
    00288     }
    00289
    00290     void broadcast()
    00291     {
    00292 #if __GTHREADS
    00293       if (__gthread_active_p())
    00294     {
    00295       if (__gthread_cond_broadcast(&_M_cond) != 0)
    00296         __throw_concurrence_broadcast_error();
    00297     }
    00298 #endif
    00299     }
    00300
    00301     void wait(__mutex *mutex)
    00302     {
    00303 #if __GTHREADS
    00304       {
    00305       if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0)
    00306         __throw_concurrence_wait_error();
    00307       }
    00308 #endif
    00309     }
    00310
    00311     void wait_recursive(__recursive_mutex *mutex)
    00312     {
    00313 #if __GTHREADS
    00314       {
    00315       if (__gthread_cond_wait_recursive(&_M_cond,
    00316                         mutex->gthread_recursive_mutex())
    00317           != 0)
    00318         __throw_concurrence_wait_error();
    00319       }
    00320 #endif
    00321     }
    00322   };
    00323 #endif
    00324
    00325 _GLIBCXX_END_NAMESPACE
    00326
    00327 #endif