(root)/
gcc-13.2.0/
libstdc++-v3/
include/
ext/
concurrence.h
       1  // Support for concurrent programing -*- C++ -*-
       2  
       3  // Copyright (C) 2003-2023 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    _GLIBCXX17_INLINE const _Lock_policy __default_lock_policy =
      54  #ifndef __GTHREADS
      55    _S_single;
      56  #elif defined _GLIBCXX_HAVE_ATOMIC_LOCK_POLICY
      57    _S_atomic;
      58  #else
      59    _S_mutex;
      60  #endif
      61  
      62    // NB: As this is used in libsupc++, need to only depend on
      63    // exception. No stdexception classes, no use of std::string.
      64    class __concurrence_lock_error : public std::exception
      65    {
      66    public:
      67      virtual char const*
      68      what() const throw()
      69      { return "__gnu_cxx::__concurrence_lock_error"; }
      70    };
      71  
      72    class __concurrence_unlock_error : public std::exception
      73    {
      74    public:
      75      virtual char const*
      76      what() const throw()
      77      { return "__gnu_cxx::__concurrence_unlock_error"; }
      78    };
      79  
      80    class __concurrence_broadcast_error : public std::exception
      81    {
      82    public:
      83      virtual char const*
      84      what() const throw()
      85      { return "__gnu_cxx::__concurrence_broadcast_error"; }
      86    };
      87  
      88    class __concurrence_wait_error : public std::exception
      89    {
      90    public:
      91      virtual char const*
      92      what() const throw()
      93      { return "__gnu_cxx::__concurrence_wait_error"; }
      94    };
      95  
      96    // Substitute for concurrence_error object in the case of -fno-exceptions.
      97    inline void
      98    __throw_concurrence_lock_error()
      99    { _GLIBCXX_THROW_OR_ABORT(__concurrence_lock_error()); }
     100  
     101    inline void
     102    __throw_concurrence_unlock_error()
     103    { _GLIBCXX_THROW_OR_ABORT(__concurrence_unlock_error()); }
     104  
     105  #ifdef __GTHREAD_HAS_COND
     106    inline void
     107    __throw_concurrence_broadcast_error()
     108    { _GLIBCXX_THROW_OR_ABORT(__concurrence_broadcast_error()); }
     109  
     110    inline void
     111    __throw_concurrence_wait_error()
     112    { _GLIBCXX_THROW_OR_ABORT(__concurrence_wait_error()); }
     113  #endif
     114   
     115    class __mutex 
     116    {
     117    private:
     118  #if __GTHREADS && defined __GTHREAD_MUTEX_INIT
     119      __gthread_mutex_t _M_mutex = __GTHREAD_MUTEX_INIT;
     120  #else
     121      __gthread_mutex_t _M_mutex;
     122  #endif
     123  
     124      __mutex(const __mutex&);
     125      __mutex& operator=(const __mutex&);
     126  
     127    public:
     128      __mutex() 
     129      { 
     130  #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT
     131        if (__gthread_active_p())
     132  	__GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
     133  #endif
     134      }
     135  
     136  #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT
     137      ~__mutex() 
     138      { 
     139        if (__gthread_active_p())
     140  	__gthread_mutex_destroy(&_M_mutex); 
     141      }
     142  #endif 
     143  
     144      void lock()
     145      {
     146  #if __GTHREADS
     147        if (__gthread_active_p())
     148  	{
     149  	  if (__gthread_mutex_lock(&_M_mutex) != 0)
     150  	    __throw_concurrence_lock_error();
     151  	}
     152  #endif
     153      }
     154      
     155      void unlock()
     156      {
     157  #if __GTHREADS
     158        if (__gthread_active_p())
     159  	{
     160  	  if (__gthread_mutex_unlock(&_M_mutex) != 0)
     161  	    __throw_concurrence_unlock_error();
     162  	}
     163  #endif
     164      }
     165  
     166      __gthread_mutex_t* gthread_mutex(void)
     167        { return &_M_mutex; }
     168    };
     169  
     170    class __recursive_mutex 
     171    {
     172    private:
     173  #if __GTHREADS && defined __GTHREAD_RECURSIVE_MUTEX_INIT
     174      __gthread_recursive_mutex_t _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT;
     175  #else
     176      __gthread_recursive_mutex_t _M_mutex;
     177  #endif
     178  
     179      __recursive_mutex(const __recursive_mutex&);
     180      __recursive_mutex& operator=(const __recursive_mutex&);
     181  
     182    public:
     183      __recursive_mutex() 
     184      { 
     185  #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT
     186        if (__gthread_active_p())
     187  	__GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
     188  #endif
     189      }
     190  
     191  #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT
     192      ~__recursive_mutex()
     193      {
     194        if (__gthread_active_p())
     195  	__gthread_recursive_mutex_destroy(&_M_mutex);
     196      }
     197  #endif
     198  
     199      void lock()
     200      { 
     201  #if __GTHREADS
     202        if (__gthread_active_p())
     203  	{
     204  	  if (__gthread_recursive_mutex_lock(&_M_mutex) != 0)
     205  	    __throw_concurrence_lock_error();
     206  	}
     207  #endif
     208      }
     209      
     210      void unlock()
     211      { 
     212  #if __GTHREADS
     213        if (__gthread_active_p())
     214  	{
     215  	  if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0)
     216  	    __throw_concurrence_unlock_error();
     217  	}
     218  #endif
     219      }
     220  
     221      __gthread_recursive_mutex_t* gthread_recursive_mutex(void)
     222      { return &_M_mutex; }
     223    };
     224  
     225    /// Scoped lock idiom.
     226    // Acquire the mutex here with a constructor call, then release with
     227    // the destructor call in accordance with RAII style.
     228    class __scoped_lock
     229    {
     230    public:
     231      typedef __mutex __mutex_type;
     232  
     233    private:
     234      __mutex_type& _M_device;
     235  
     236      __scoped_lock(const __scoped_lock&);
     237      __scoped_lock& operator=(const __scoped_lock&);
     238  
     239    public:
     240      explicit __scoped_lock(__mutex_type& __name) : _M_device(__name)
     241      { _M_device.lock(); }
     242  
     243      ~__scoped_lock() throw()
     244      { _M_device.unlock(); }
     245    };
     246  
     247  #ifdef __GTHREAD_HAS_COND
     248    class __cond
     249    {
     250    private:
     251  #if __GTHREADS && defined __GTHREAD_COND_INIT
     252      __gthread_cond_t _M_cond = __GTHREAD_COND_INIT;
     253  #else
     254      __gthread_cond_t _M_cond;
     255  #endif
     256  
     257      __cond(const __cond&);
     258      __cond& operator=(const __cond&);
     259  
     260    public:
     261      __cond() 
     262      { 
     263  #if __GTHREADS && ! defined __GTHREAD_COND_INIT
     264        if (__gthread_active_p())
     265  	__GTHREAD_COND_INIT_FUNCTION(&_M_cond);
     266  #endif
     267      }
     268  
     269  #if __GTHREADS && ! defined __GTHREAD_COND_INIT
     270      ~__cond() 
     271      { 
     272        if (__gthread_active_p())
     273  	__gthread_cond_destroy(&_M_cond); 
     274      }
     275  #endif 
     276  
     277      void broadcast()
     278      {
     279  #if __GTHREADS
     280        if (__gthread_active_p())
     281  	{
     282  	  if (__gthread_cond_broadcast(&_M_cond) != 0)
     283  	    __throw_concurrence_broadcast_error();
     284  	}
     285  #endif
     286      }
     287  
     288      void wait(__mutex *mutex)
     289      {
     290  #if __GTHREADS
     291        {
     292  	  if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0)
     293  	    __throw_concurrence_wait_error();
     294        }
     295  #endif
     296      }
     297  
     298      void wait_recursive(__recursive_mutex *mutex)
     299      {
     300  #if __GTHREADS
     301        {
     302  	  if (__gthread_cond_wait_recursive(&_M_cond,
     303  					    mutex->gthread_recursive_mutex())
     304  	      != 0)
     305  	    __throw_concurrence_wait_error();
     306        }
     307  #endif
     308      }
     309    };
     310  #endif
     311  
     312  _GLIBCXX_END_NAMESPACE_VERSION
     313  } // namespace
     314  
     315  #endif