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