Home | History | Annotate | Download | only in ext
      1 // Support for concurrent programing -*- C++ -*-
      2 
      3 // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009
      4 // Free Software Foundation, Inc.
      5 //
      6 // This file is part of the GNU ISO C++ Library.  This library is free
      7 // software; you can redistribute it and/or modify it under the
      8 // terms of the GNU General Public License as published by the
      9 // Free Software Foundation; either version 3, or (at your option)
     10 // any later version.
     11 
     12 // This library is distributed in the hope that it will be useful,
     13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 // GNU General Public License for more details.
     16 
     17 // Under Section 7 of GPL version 3, you are granted additional
     18 // permissions described in the GCC Runtime Library Exception, version
     19 // 3.1, as published by the Free Software Foundation.
     20 
     21 // You should have received a copy of the GNU General Public License and
     22 // a copy of the GCC Runtime Library Exception along with this program;
     23 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     24 // <http://www.gnu.org/licenses/>.
     25 
     26 /** @file concurrence.h
     27  *  This is an internal header file, included by other library headers.
     28  *  You should not attempt to use it directly.
     29  */
     30 
     31 #ifndef _CONCURRENCE_H
     32 #define _CONCURRENCE_H 1
     33 
     34 #include <exception>
     35 #include <bits/gthr.h>
     36 #include <bits/functexcept.h>
     37 
     38 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
     39 
     40   // Available locking policies:
     41   // _S_single    single-threaded code that doesn't need to be locked.
     42   // _S_mutex     multi-threaded code that requires additional support
     43   //              from gthr.h or abstraction layers in concurrence.h.
     44   // _S_atomic    multi-threaded code using atomic operations.
     45   enum _Lock_policy { _S_single, _S_mutex, _S_atomic };
     46 
     47   // Compile time constant that indicates prefered locking policy in
     48   // the current configuration.
     49   static const _Lock_policy __default_lock_policy =
     50 #ifdef __GTHREADS
     51 #if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) \
     52      && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4))
     53   _S_atomic;
     54 #else
     55   _S_mutex;
     56 #endif
     57 #else
     58   _S_single;
     59 #endif
     60 
     61   // NB: As this is used in libsupc++, need to only depend on
     62   // exception. No stdexception classes, no use of std::string.
     63   class __concurrence_lock_error : public std::exception
     64   {
     65   public:
     66     virtual char const*
     67     what() const throw()
     68     { return "__gnu_cxx::__concurrence_lock_error"; }
     69   };
     70 
     71   class __concurrence_unlock_error : public std::exception
     72   {
     73   public:
     74     virtual char const*
     75     what() const throw()
     76     { return "__gnu_cxx::__concurrence_unlock_error"; }
     77   };
     78 
     79   class __concurrence_broadcast_error : public std::exception
     80   {
     81   public:
     82     virtual char const*
     83     what() const throw()
     84     { return "__gnu_cxx::__concurrence_broadcast_error"; }
     85   };
     86 
     87   class __concurrence_wait_error : public std::exception
     88   {
     89   public:
     90     virtual char const*
     91     what() const throw()
     92     { return "__gnu_cxx::__concurrence_wait_error"; }
     93   };
     94 
     95   // Substitute for concurrence_error object in the case of -fno-exceptions.
     96   inline void
     97   __throw_concurrence_lock_error()
     98   {
     99 #if __EXCEPTIONS
    100     throw __concurrence_lock_error();
    101 #else
    102     __builtin_abort();
    103 #endif
    104   }
    105 
    106   inline void
    107   __throw_concurrence_unlock_error()
    108   {
    109 #if __EXCEPTIONS
    110     throw __concurrence_unlock_error();
    111 #else
    112     __builtin_abort();
    113 #endif
    114   }
    115 
    116 #ifdef __GTHREAD_HAS_COND
    117   inline void
    118   __throw_concurrence_broadcast_error()
    119   {
    120 #if __EXCEPTIONS
    121     throw __concurrence_broadcast_error();
    122 #else
    123     __builtin_abort();
    124 #endif
    125   }
    126 
    127   inline void
    128   __throw_concurrence_wait_error()
    129   {
    130 #if __EXCEPTIONS
    131     throw __concurrence_wait_error();
    132 #else
    133     __builtin_abort();
    134 #endif
    135   }
    136 #endif
    137 
    138   class __mutex
    139   {
    140   private:
    141     __gthread_mutex_t _M_mutex;
    142 
    143     __mutex(const __mutex&);
    144     __mutex& operator=(const __mutex&);
    145 
    146   public:
    147     __mutex()
    148     {
    149 #if __GTHREADS
    150       if (__gthread_active_p())
    151 	{
    152 #if defined __GTHREAD_MUTEX_INIT
    153 	  __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
    154 	  _M_mutex = __tmp;
    155 #else
    156 	  __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
    157 #endif
    158 	}
    159 #endif
    160     }
    161 
    162     void lock()
    163     {
    164 #if __GTHREADS
    165       if (__gthread_active_p())
    166 	{
    167 	  if (__gthread_mutex_lock(&_M_mutex) != 0)
    168 	    __throw_concurrence_lock_error();
    169 	}
    170 #endif
    171     }
    172 
    173     void unlock()
    174     {
    175 #if __GTHREADS
    176       if (__gthread_active_p())
    177 	{
    178 	  if (__gthread_mutex_unlock(&_M_mutex) != 0)
    179 	    __throw_concurrence_unlock_error();
    180 	}
    181 #endif
    182     }
    183 
    184     __gthread_mutex_t* gthread_mutex(void)
    185       { return &_M_mutex; }
    186   };
    187 
    188   class __recursive_mutex
    189   {
    190   private:
    191     __gthread_recursive_mutex_t _M_mutex;
    192 
    193     __recursive_mutex(const __recursive_mutex&);
    194     __recursive_mutex& operator=(const __recursive_mutex&);
    195 
    196   public:
    197     __recursive_mutex()
    198     {
    199 #if __GTHREADS
    200       if (__gthread_active_p())
    201 	{
    202 #if defined __GTHREAD_RECURSIVE_MUTEX_INIT
    203 	  __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT;
    204 	  _M_mutex = __tmp;
    205 #else
    206 	  __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
    207 #endif
    208 	}
    209 #endif
    210     }
    211 
    212     void lock()
    213     {
    214 #if __GTHREADS
    215       if (__gthread_active_p())
    216 	{
    217 	  if (__gthread_recursive_mutex_lock(&_M_mutex) != 0)
    218 	    __throw_concurrence_lock_error();
    219 	}
    220 #endif
    221     }
    222 
    223     void unlock()
    224     {
    225 #if __GTHREADS
    226       if (__gthread_active_p())
    227 	{
    228 	  if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0)
    229 	    __throw_concurrence_unlock_error();
    230 	}
    231 #endif
    232     }
    233 
    234     __gthread_recursive_mutex_t* gthread_recursive_mutex(void)
    235       { return &_M_mutex; }
    236   };
    237 
    238   /// Scoped lock idiom.
    239   // Acquire the mutex here with a constructor call, then release with
    240   // the destructor call in accordance with RAII style.
    241   class __scoped_lock
    242   {
    243   public:
    244     typedef __mutex __mutex_type;
    245 
    246   private:
    247     __mutex_type& _M_device;
    248 
    249     __scoped_lock(const __scoped_lock&);
    250     __scoped_lock& operator=(const __scoped_lock&);
    251 
    252   public:
    253     explicit __scoped_lock(__mutex_type& __name) : _M_device(__name)
    254     { _M_device.lock(); }
    255 
    256     ~__scoped_lock() throw()
    257     { _M_device.unlock(); }
    258   };
    259 
    260 #ifdef __GTHREAD_HAS_COND
    261   class __cond
    262   {
    263   private:
    264     __gthread_cond_t _M_cond;
    265 
    266     __cond(const __cond&);
    267     __cond& operator=(const __cond&);
    268 
    269   public:
    270     __cond()
    271     {
    272 #if __GTHREADS
    273       if (__gthread_active_p())
    274 	{
    275 #if defined __GTHREAD_COND_INIT
    276 	  __gthread_cond_t __tmp = __GTHREAD_COND_INIT;
    277 	  _M_cond = __tmp;
    278 #else
    279 	  __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
    280 #endif
    281 	}
    282 #endif
    283     }
    284 
    285     void broadcast()
    286     {
    287 #if __GTHREADS
    288       if (__gthread_active_p())
    289 	{
    290 	  if (__gthread_cond_broadcast(&_M_cond) != 0)
    291 	    __throw_concurrence_broadcast_error();
    292 	}
    293 #endif
    294     }
    295 
    296     void wait(__mutex *mutex)
    297     {
    298 #if __GTHREADS
    299       {
    300 	  if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0)
    301 	    __throw_concurrence_wait_error();
    302       }
    303 #endif
    304     }
    305 
    306     void wait_recursive(__recursive_mutex *mutex)
    307     {
    308 #if __GTHREADS
    309       {
    310 	  if (__gthread_cond_wait_recursive(&_M_cond,
    311 					    mutex->gthread_recursive_mutex())
    312 	      != 0)
    313 	    __throw_concurrence_wait_error();
    314       }
    315 #endif
    316     }
    317   };
    318 #endif
    319 
    320 _GLIBCXX_END_NAMESPACE
    321 
    322 #endif
    323