1  // std::mutex implementation -*- 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 bits/std_mutex.h
      26   *  This is an internal header file, included by other library headers.
      27   *  Do not attempt to use it directly. @headername{mutex}
      28   */
      29  
      30  #ifndef _GLIBCXX_MUTEX_H
      31  #define _GLIBCXX_MUTEX_H 1
      32  
      33  #pragma GCC system_header
      34  
      35  #if __cplusplus < 201103L
      36  # include <bits/c++0x_warning.h>
      37  #else
      38  
      39  #include <errno.h> // EBUSY
      40  #include <bits/functexcept.h>
      41  #include <bits/gthr.h>
      42  
      43  namespace std _GLIBCXX_VISIBILITY(default)
      44  {
      45  _GLIBCXX_BEGIN_NAMESPACE_VERSION
      46  
      47    /**
      48     * @defgroup mutexes Mutexes
      49     * @ingroup concurrency
      50     *
      51     * Classes for mutex support.
      52     * @{
      53     */
      54  
      55  #ifdef _GLIBCXX_HAS_GTHREADS
      56    /// @cond undocumented
      57  
      58    // Common base class for std::mutex and std::timed_mutex
      59    class __mutex_base
      60    {
      61    protected:
      62      typedef __gthread_mutex_t			__native_type;
      63  
      64  #ifdef __GTHREAD_MUTEX_INIT
      65      __native_type  _M_mutex = __GTHREAD_MUTEX_INIT;
      66  
      67      constexpr __mutex_base() noexcept = default;
      68  #else
      69      __native_type  _M_mutex;
      70  
      71      __mutex_base() noexcept
      72      {
      73        // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
      74        __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
      75      }
      76  
      77      ~__mutex_base() noexcept { __gthread_mutex_destroy(&_M_mutex); }
      78  #endif
      79  
      80      __mutex_base(const __mutex_base&) = delete;
      81      __mutex_base& operator=(const __mutex_base&) = delete;
      82    };
      83    /// @endcond
      84  
      85    /** The standard mutex type.
      86     *
      87     * A simple, non-recursive, non-timed mutex.
      88     *
      89     * Do not call `lock()` and `unlock()` directly, use a scoped lock type
      90     * such as `std::unique_lock`, `std::lock_guard`, or (since C++17)
      91     * `std::scoped_lock`.
      92     *
      93     * @headerfile mutex
      94     * @since C++11
      95     */
      96    class mutex : private __mutex_base
      97    {
      98    public:
      99      typedef __native_type* 			native_handle_type;
     100  
     101  #ifdef __GTHREAD_MUTEX_INIT
     102      constexpr
     103  #endif
     104      mutex() noexcept = default;
     105      ~mutex() = default;
     106  
     107      mutex(const mutex&) = delete;
     108      mutex& operator=(const mutex&) = delete;
     109  
     110      void
     111      lock()
     112      {
     113        int __e = __gthread_mutex_lock(&_M_mutex);
     114  
     115        // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
     116        if (__e)
     117  	__throw_system_error(__e);
     118      }
     119  
     120      _GLIBCXX_NODISCARD
     121      bool
     122      try_lock() noexcept
     123      {
     124        // XXX EINVAL, EAGAIN, EBUSY
     125        return !__gthread_mutex_trylock(&_M_mutex);
     126      }
     127  
     128      void
     129      unlock()
     130      {
     131        // XXX EINVAL, EAGAIN, EPERM
     132        __gthread_mutex_unlock(&_M_mutex);
     133      }
     134  
     135      native_handle_type
     136      native_handle() noexcept
     137      { return &_M_mutex; }
     138    };
     139  
     140    /// @cond undocumented
     141  
     142    // Implementation details for std::condition_variable
     143    class __condvar
     144    {
     145      using timespec = __gthread_time_t;
     146  
     147    public:
     148      __condvar() noexcept
     149      {
     150  #ifndef __GTHREAD_COND_INIT
     151        __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
     152  #endif
     153      }
     154  
     155      ~__condvar()
     156      {
     157        int __e __attribute__((__unused__)) = __gthread_cond_destroy(&_M_cond);
     158        __glibcxx_assert(__e != EBUSY); // threads are still blocked
     159      }
     160  
     161      __condvar(const __condvar&) = delete;
     162      __condvar& operator=(const __condvar&) = delete;
     163  
     164      __gthread_cond_t* native_handle() noexcept { return &_M_cond; }
     165  
     166      // Expects: Calling thread has locked __m.
     167      void
     168      wait(mutex& __m)
     169      {
     170        int __e __attribute__((__unused__))
     171  	= __gthread_cond_wait(&_M_cond, __m.native_handle());
     172        __glibcxx_assert(__e == 0);
     173      }
     174  
     175      void
     176      wait_until(mutex& __m, timespec& __abs_time)
     177      {
     178        __gthread_cond_timedwait(&_M_cond, __m.native_handle(), &__abs_time);
     179      }
     180  
     181  #ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
     182      void
     183      wait_until(mutex& __m, clockid_t __clock, timespec& __abs_time)
     184      {
     185        pthread_cond_clockwait(&_M_cond, __m.native_handle(), __clock,
     186  			     &__abs_time);
     187      }
     188  #endif
     189  
     190      void
     191      notify_one() noexcept
     192      {
     193        int __e __attribute__((__unused__)) = __gthread_cond_signal(&_M_cond);
     194        __glibcxx_assert(__e == 0);
     195      }
     196  
     197      void
     198      notify_all() noexcept
     199      {
     200        int __e __attribute__((__unused__)) = __gthread_cond_broadcast(&_M_cond);
     201        __glibcxx_assert(__e == 0);
     202      }
     203  
     204    protected:
     205  #ifdef __GTHREAD_COND_INIT
     206      __gthread_cond_t _M_cond = __GTHREAD_COND_INIT;
     207  #else
     208      __gthread_cond_t _M_cond;
     209  #endif
     210    };
     211    /// @endcond
     212  
     213  #endif // _GLIBCXX_HAS_GTHREADS
     214  
     215    /// Do not acquire ownership of the mutex.
     216    struct defer_lock_t { explicit defer_lock_t() = default; };
     217  
     218    /// Try to acquire ownership of the mutex without blocking.
     219    struct try_to_lock_t { explicit try_to_lock_t() = default; };
     220  
     221    /// Assume the calling thread has already obtained mutex ownership
     222    /// and manage it.
     223    struct adopt_lock_t { explicit adopt_lock_t() = default; };
     224  
     225    /// Tag used to prevent a scoped lock from acquiring ownership of a mutex.
     226    _GLIBCXX17_INLINE constexpr defer_lock_t	defer_lock { };
     227  
     228    /// Tag used to prevent a scoped lock from blocking if a mutex is locked.
     229    _GLIBCXX17_INLINE constexpr try_to_lock_t	try_to_lock { };
     230  
     231    /// Tag used to make a scoped lock take ownership of a locked mutex.
     232    _GLIBCXX17_INLINE constexpr adopt_lock_t	adopt_lock { };
     233  
     234    /** @brief A simple scoped lock type.
     235     *
     236     * A lock_guard controls mutex ownership within a scope, releasing
     237     * ownership in the destructor.
     238     *
     239     * @headerfile mutex
     240     * @since C++11
     241     */
     242    template<typename _Mutex>
     243      class lock_guard
     244      {
     245      public:
     246        typedef _Mutex mutex_type;
     247  
     248        explicit lock_guard(mutex_type& __m) : _M_device(__m)
     249        { _M_device.lock(); }
     250  
     251        lock_guard(mutex_type& __m, adopt_lock_t) noexcept : _M_device(__m)
     252        { } // calling thread owns mutex
     253  
     254        ~lock_guard()
     255        { _M_device.unlock(); }
     256  
     257        lock_guard(const lock_guard&) = delete;
     258        lock_guard& operator=(const lock_guard&) = delete;
     259  
     260      private:
     261        mutex_type&  _M_device;
     262      };
     263  
     264    /// @} group mutexes
     265  _GLIBCXX_END_NAMESPACE_VERSION
     266  } // namespace
     267  #endif // C++11
     268  #endif // _GLIBCXX_MUTEX_H