(root)/
gcc-13.2.0/
libstdc++-v3/
include/
bits/
shared_ptr_atomic.h
       1  // shared_ptr atomic access -*- C++ -*-
       2  
       3  // Copyright (C) 2014-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/shared_ptr_atomic.h
      26   *  This is an internal header file, included by other library headers.
      27   *  Do not attempt to use it directly. @headername{memory}
      28   */
      29  
      30  #ifndef _SHARED_PTR_ATOMIC_H
      31  #define _SHARED_PTR_ATOMIC_H 1
      32  
      33  #include <bits/atomic_base.h>
      34  
      35  // Annotations for the custom locking in atomic<shared_ptr<T>>.
      36  #if defined _GLIBCXX_TSAN && __has_include(<sanitizer/tsan_interface.h>)
      37  #include <sanitizer/tsan_interface.h>
      38  #define _GLIBCXX_TSAN_MUTEX_DESTROY(X) \
      39    __tsan_mutex_destroy(X, __tsan_mutex_not_static)
      40  #define _GLIBCXX_TSAN_MUTEX_TRY_LOCK(X) \
      41    __tsan_mutex_pre_lock(X, __tsan_mutex_not_static|__tsan_mutex_try_lock)
      42  #define _GLIBCXX_TSAN_MUTEX_TRY_LOCK_FAILED(X) __tsan_mutex_post_lock(X, \
      43      __tsan_mutex_not_static|__tsan_mutex_try_lock_failed, 0)
      44  #define _GLIBCXX_TSAN_MUTEX_LOCKED(X) \
      45    __tsan_mutex_post_lock(X, __tsan_mutex_not_static, 0)
      46  #define _GLIBCXX_TSAN_MUTEX_PRE_UNLOCK(X) __tsan_mutex_pre_unlock(X, 0)
      47  #define _GLIBCXX_TSAN_MUTEX_POST_UNLOCK(X) __tsan_mutex_post_unlock(X, 0)
      48  #define _GLIBCXX_TSAN_MUTEX_PRE_SIGNAL(X) __tsan_mutex_pre_signal(X, 0)
      49  #define _GLIBCXX_TSAN_MUTEX_POST_SIGNAL(X) __tsan_mutex_post_signal(X, 0)
      50  #else
      51  #define _GLIBCXX_TSAN_MUTEX_DESTROY(X)
      52  #define _GLIBCXX_TSAN_MUTEX_TRY_LOCK(X)
      53  #define _GLIBCXX_TSAN_MUTEX_TRY_LOCK_FAILED(X)
      54  #define _GLIBCXX_TSAN_MUTEX_LOCKED(X)
      55  #define _GLIBCXX_TSAN_MUTEX_PRE_UNLOCK(X)
      56  #define _GLIBCXX_TSAN_MUTEX_POST_UNLOCK(X)
      57  #define _GLIBCXX_TSAN_MUTEX_PRE_SIGNAL(X)
      58  #define _GLIBCXX_TSAN_MUTEX_POST_SIGNAL(X)
      59  #endif
      60  
      61  namespace std _GLIBCXX_VISIBILITY(default)
      62  {
      63  _GLIBCXX_BEGIN_NAMESPACE_VERSION
      64  
      65    /**
      66     * @addtogroup pointer_abstractions
      67     * @relates shared_ptr
      68     * @{
      69     */
      70  
      71    /// @cond undocumented
      72  
      73    struct _Sp_locker
      74    {
      75      _Sp_locker(const _Sp_locker&) = delete;
      76      _Sp_locker& operator=(const _Sp_locker&) = delete;
      77  
      78  #ifdef __GTHREADS
      79      explicit
      80      _Sp_locker(const void*) noexcept;
      81      _Sp_locker(const void*, const void*) noexcept;
      82      ~_Sp_locker();
      83  
      84    private:
      85      unsigned char _M_key1;
      86      unsigned char _M_key2;
      87  #else
      88      explicit _Sp_locker(const void*, const void* = nullptr) { }
      89  #endif
      90    };
      91  
      92    /// @endcond
      93  
      94    /**
      95     *  @brief  Report whether shared_ptr atomic operations are lock-free.
      96     *  @param  __p A non-null pointer to a shared_ptr object.
      97     *  @return True if atomic access to @c *__p is lock-free, false otherwise.
      98     *  @{
      99    */
     100    template<typename _Tp, _Lock_policy _Lp>
     101      inline bool
     102      atomic_is_lock_free(const __shared_ptr<_Tp, _Lp>* __p)
     103      {
     104  #ifdef __GTHREADS
     105        return __gthread_active_p() == 0;
     106  #else
     107        return true;
     108  #endif
     109      }
     110  
     111    template<typename _Tp>
     112      inline bool
     113      atomic_is_lock_free(const shared_ptr<_Tp>* __p)
     114      { return std::atomic_is_lock_free<_Tp, __default_lock_policy>(__p); }
     115  
     116    /// @}
     117  
     118    /**
     119     *  @brief  Atomic load for shared_ptr objects.
     120     *  @param  __p A non-null pointer to a shared_ptr object.
     121     *  @return @c *__p
     122     *
     123     *  The memory order shall not be `memory_order_release` or
     124     *  `memory_order_acq_rel`.
     125     *  @{
     126    */
     127    template<typename _Tp>
     128      inline shared_ptr<_Tp>
     129      atomic_load_explicit(const shared_ptr<_Tp>* __p, memory_order)
     130      {
     131        _Sp_locker __lock{__p};
     132        return *__p;
     133      }
     134  
     135    template<typename _Tp>
     136      inline shared_ptr<_Tp>
     137      atomic_load(const shared_ptr<_Tp>* __p)
     138      { return std::atomic_load_explicit(__p, memory_order_seq_cst); }
     139  
     140    template<typename _Tp, _Lock_policy _Lp>
     141      inline __shared_ptr<_Tp, _Lp>
     142      atomic_load_explicit(const __shared_ptr<_Tp, _Lp>* __p, memory_order)
     143      {
     144        _Sp_locker __lock{__p};
     145        return *__p;
     146      }
     147  
     148    template<typename _Tp, _Lock_policy _Lp>
     149      inline __shared_ptr<_Tp, _Lp>
     150      atomic_load(const __shared_ptr<_Tp, _Lp>* __p)
     151      { return std::atomic_load_explicit(__p, memory_order_seq_cst); }
     152    /// @}
     153  
     154    /**
     155     *  @brief  Atomic store for shared_ptr objects.
     156     *  @param  __p A non-null pointer to a shared_ptr object.
     157     *  @param  __r The value to store.
     158     *
     159     *  The memory order shall not be `memory_order_acquire` or
     160     *  `memory_order_acq_rel`.
     161     *  @{
     162    */
     163    template<typename _Tp>
     164      inline void
     165      atomic_store_explicit(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r,
     166  			  memory_order)
     167      {
     168        _Sp_locker __lock{__p};
     169        __p->swap(__r); // use swap so that **__p not destroyed while lock held
     170      }
     171  
     172    template<typename _Tp>
     173      inline void
     174      atomic_store(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r)
     175      { std::atomic_store_explicit(__p, std::move(__r), memory_order_seq_cst); }
     176  
     177    template<typename _Tp, _Lock_policy _Lp>
     178      inline void
     179      atomic_store_explicit(__shared_ptr<_Tp, _Lp>* __p,
     180  			  __shared_ptr<_Tp, _Lp> __r,
     181  			  memory_order)
     182      {
     183        _Sp_locker __lock{__p};
     184        __p->swap(__r); // use swap so that **__p not destroyed while lock held
     185      }
     186  
     187    template<typename _Tp, _Lock_policy _Lp>
     188      inline void
     189      atomic_store(__shared_ptr<_Tp, _Lp>* __p, __shared_ptr<_Tp, _Lp> __r)
     190      { std::atomic_store_explicit(__p, std::move(__r), memory_order_seq_cst); }
     191    /// @}
     192  
     193    /**
     194     *  @brief  Atomic exchange for shared_ptr objects.
     195     *  @param  __p A non-null pointer to a shared_ptr object.
     196     *  @param  __r New value to store in `*__p`.
     197     *  @return The original value of `*__p`
     198     *  @{
     199    */
     200    template<typename _Tp>
     201      inline shared_ptr<_Tp>
     202      atomic_exchange_explicit(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r,
     203  			     memory_order)
     204      {
     205        _Sp_locker __lock{__p};
     206        __p->swap(__r);
     207        return __r;
     208      }
     209  
     210    template<typename _Tp>
     211      inline shared_ptr<_Tp>
     212      atomic_exchange(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r)
     213      {
     214        return std::atomic_exchange_explicit(__p, std::move(__r),
     215  					   memory_order_seq_cst);
     216      }
     217  
     218    template<typename _Tp, _Lock_policy _Lp>
     219      inline __shared_ptr<_Tp, _Lp>
     220      atomic_exchange_explicit(__shared_ptr<_Tp, _Lp>* __p,
     221  			     __shared_ptr<_Tp, _Lp> __r,
     222  			     memory_order)
     223      {
     224        _Sp_locker __lock{__p};
     225        __p->swap(__r);
     226        return __r;
     227      }
     228  
     229    template<typename _Tp, _Lock_policy _Lp>
     230      inline __shared_ptr<_Tp, _Lp>
     231      atomic_exchange(__shared_ptr<_Tp, _Lp>* __p, __shared_ptr<_Tp, _Lp> __r)
     232      {
     233        return std::atomic_exchange_explicit(__p, std::move(__r),
     234  					   memory_order_seq_cst);
     235      }
     236    /// @}
     237  
     238    /**
     239     *  @brief  Atomic compare-and-swap for shared_ptr objects.
     240     *  @param  __p A non-null pointer to a shared_ptr object.
     241     *  @param  __v A non-null pointer to a shared_ptr object.
     242     *  @param  __w A non-null pointer to a shared_ptr object.
     243     *  @return True if `*__p` was equivalent to `*__v`, false otherwise.
     244     *
     245     *  The memory order for failure shall not be `memory_order_release` or
     246     *  `memory_order_acq_rel`.
     247     *  @{
     248    */
     249    template<typename _Tp>
     250      bool
     251      atomic_compare_exchange_strong_explicit(shared_ptr<_Tp>* __p,
     252  					    shared_ptr<_Tp>* __v,
     253  					    shared_ptr<_Tp> __w,
     254  					    memory_order,
     255  					    memory_order)
     256      {
     257        shared_ptr<_Tp> __x; // goes out of scope after __lock
     258        _Sp_locker __lock{__p, __v};
     259        owner_less<shared_ptr<_Tp>> __less;
     260        if (*__p == *__v && !__less(*__p, *__v) && !__less(*__v, *__p))
     261  	{
     262  	  __x = std::move(*__p);
     263  	  *__p = std::move(__w);
     264  	  return true;
     265  	}
     266        __x = std::move(*__v);
     267        *__v = *__p;
     268        return false;
     269      }
     270  
     271    template<typename _Tp>
     272      inline bool
     273      atomic_compare_exchange_strong(shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v,
     274  				 shared_ptr<_Tp> __w)
     275      {
     276        return std::atomic_compare_exchange_strong_explicit(__p, __v,
     277  	  std::move(__w), memory_order_seq_cst, memory_order_seq_cst);
     278      }
     279  
     280    template<typename _Tp>
     281      inline bool
     282      atomic_compare_exchange_weak_explicit(shared_ptr<_Tp>* __p,
     283  					  shared_ptr<_Tp>* __v,
     284  					  shared_ptr<_Tp> __w,
     285  					  memory_order __success,
     286  					  memory_order __failure)
     287      {
     288        return std::atomic_compare_exchange_strong_explicit(__p, __v,
     289  	  std::move(__w), __success, __failure);
     290      }
     291  
     292    template<typename _Tp>
     293      inline bool
     294      atomic_compare_exchange_weak(shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v,
     295  				 shared_ptr<_Tp> __w)
     296      {
     297        return std::atomic_compare_exchange_weak_explicit(__p, __v,
     298  	  std::move(__w), memory_order_seq_cst, memory_order_seq_cst);
     299      }
     300  
     301    template<typename _Tp, _Lock_policy _Lp>
     302      bool
     303      atomic_compare_exchange_strong_explicit(__shared_ptr<_Tp, _Lp>* __p,
     304  					    __shared_ptr<_Tp, _Lp>* __v,
     305  					    __shared_ptr<_Tp, _Lp> __w,
     306  					    memory_order,
     307  					    memory_order)
     308      {
     309        __shared_ptr<_Tp, _Lp> __x; // goes out of scope after __lock
     310        _Sp_locker __lock{__p, __v};
     311        owner_less<__shared_ptr<_Tp, _Lp>> __less;
     312        if (*__p == *__v && !__less(*__p, *__v) && !__less(*__v, *__p))
     313  	{
     314  	  __x = std::move(*__p);
     315  	  *__p = std::move(__w);
     316  	  return true;
     317  	}
     318        __x = std::move(*__v);
     319        *__v = *__p;
     320        return false;
     321      }
     322  
     323    template<typename _Tp, _Lock_policy _Lp>
     324      inline bool
     325      atomic_compare_exchange_strong(__shared_ptr<_Tp, _Lp>* __p,
     326  				   __shared_ptr<_Tp, _Lp>* __v,
     327  				   __shared_ptr<_Tp, _Lp> __w)
     328      {
     329        return std::atomic_compare_exchange_strong_explicit(__p, __v,
     330  	  std::move(__w), memory_order_seq_cst, memory_order_seq_cst);
     331      }
     332  
     333    template<typename _Tp, _Lock_policy _Lp>
     334      inline bool
     335      atomic_compare_exchange_weak_explicit(__shared_ptr<_Tp, _Lp>* __p,
     336  					  __shared_ptr<_Tp, _Lp>* __v,
     337  					  __shared_ptr<_Tp, _Lp> __w,
     338  					  memory_order __success,
     339  					  memory_order __failure)
     340      {
     341        return std::atomic_compare_exchange_strong_explicit(__p, __v,
     342  	  std::move(__w), __success, __failure);
     343      }
     344  
     345    template<typename _Tp, _Lock_policy _Lp>
     346      inline bool
     347      atomic_compare_exchange_weak(__shared_ptr<_Tp, _Lp>* __p,
     348  				 __shared_ptr<_Tp, _Lp>* __v,
     349  				 __shared_ptr<_Tp, _Lp> __w)
     350      {
     351        return std::atomic_compare_exchange_weak_explicit(__p, __v,
     352  	  std::move(__w), memory_order_seq_cst, memory_order_seq_cst);
     353      }
     354    /// @}
     355  
     356    /// @} group pointer_abstractions
     357  
     358  #if __cplusplus >= 202002L
     359  # define __cpp_lib_atomic_shared_ptr 201711L
     360    template<typename _Tp>
     361      class atomic;
     362  
     363    /**
     364     * @addtogroup pointer_abstractions
     365     * @relates shared_ptr
     366     * @{
     367     */
     368  
     369    template<typename _Up>
     370      static constexpr bool __is_shared_ptr = false;
     371    template<typename _Up>
     372      static constexpr bool __is_shared_ptr<shared_ptr<_Up>> = true;
     373  
     374    template<typename _Tp>
     375      class _Sp_atomic
     376      {
     377        using value_type = _Tp;
     378  
     379        friend class atomic<_Tp>;
     380  
     381        // An atomic version of __shared_count<> and __weak_count<>.
     382        // Stores a _Sp_counted_base<>* but uses the LSB as a lock.
     383        struct _Atomic_count
     384        {
     385  	// Either __shared_count<> or __weak_count<>
     386  	using __count_type = decltype(_Tp::_M_refcount);
     387  
     388  	// _Sp_counted_base<>*
     389  	using pointer = decltype(__count_type::_M_pi);
     390  
     391  	// Ensure we can use the LSB as the lock bit.
     392  	static_assert(alignof(remove_pointer_t<pointer>) > 1);
     393  
     394  	constexpr _Atomic_count() noexcept = default;
     395  
     396  	explicit
     397  	_Atomic_count(__count_type&& __c) noexcept
     398  	: _M_val(reinterpret_cast<uintptr_t>(__c._M_pi))
     399  	{
     400  	  __c._M_pi = nullptr;
     401  	}
     402  
     403  	~_Atomic_count()
     404  	{
     405  	  auto __val = _M_val.load(memory_order_relaxed);
     406  	  _GLIBCXX_TSAN_MUTEX_DESTROY(&_M_val);
     407  	  __glibcxx_assert(!(__val & _S_lock_bit));
     408  	  if (auto __pi = reinterpret_cast<pointer>(__val))
     409  	    {
     410  	      if constexpr (__is_shared_ptr<_Tp>)
     411  		__pi->_M_release();
     412  	      else
     413  		__pi->_M_weak_release();
     414  	    }
     415  	}
     416  
     417  	_Atomic_count(const _Atomic_count&) = delete;
     418  	_Atomic_count& operator=(const _Atomic_count&) = delete;
     419  
     420  	// Precondition: Caller does not hold lock!
     421  	// Returns the raw pointer value without the lock bit set.
     422  	pointer
     423  	lock(memory_order __o) const noexcept
     424  	{
     425  	  // To acquire the lock we flip the LSB from 0 to 1.
     426  
     427  	  auto __current = _M_val.load(memory_order_relaxed);
     428  	  while (__current & _S_lock_bit)
     429  	    {
     430  #if __cpp_lib_atomic_wait
     431  	      __detail::__thread_relax();
     432  #endif
     433  	      __current = _M_val.load(memory_order_relaxed);
     434  	    }
     435  
     436  	  _GLIBCXX_TSAN_MUTEX_TRY_LOCK(&_M_val);
     437  
     438  	  while (!_M_val.compare_exchange_strong(__current,
     439  						 __current | _S_lock_bit,
     440  						 __o,
     441  						 memory_order_relaxed))
     442  	    {
     443  	      _GLIBCXX_TSAN_MUTEX_TRY_LOCK_FAILED(&_M_val);
     444  #if __cpp_lib_atomic_wait
     445  	      __detail::__thread_relax();
     446  #endif
     447  	      __current = __current & ~_S_lock_bit;
     448  	      _GLIBCXX_TSAN_MUTEX_TRY_LOCK(&_M_val);
     449  	    }
     450  	  _GLIBCXX_TSAN_MUTEX_LOCKED(&_M_val);
     451  	  return reinterpret_cast<pointer>(__current);
     452  	}
     453  
     454  	// Precondition: caller holds lock!
     455  	void
     456  	unlock(memory_order __o) const noexcept
     457  	{
     458  	  _GLIBCXX_TSAN_MUTEX_PRE_UNLOCK(&_M_val);
     459  	  _M_val.fetch_sub(1, __o);
     460  	  _GLIBCXX_TSAN_MUTEX_POST_UNLOCK(&_M_val);
     461  	}
     462  
     463  	// Swaps the values of *this and __c, and unlocks *this.
     464  	// Precondition: caller holds lock!
     465  	void
     466  	_M_swap_unlock(__count_type& __c, memory_order __o) noexcept
     467  	{
     468  	  if (__o != memory_order_seq_cst)
     469  	    __o = memory_order_release;
     470  	  auto __x = reinterpret_cast<uintptr_t>(__c._M_pi);
     471  	  _GLIBCXX_TSAN_MUTEX_PRE_UNLOCK(&_M_val);
     472  	  __x = _M_val.exchange(__x, __o);
     473  	  _GLIBCXX_TSAN_MUTEX_POST_UNLOCK(&_M_val);
     474  	  __c._M_pi = reinterpret_cast<pointer>(__x & ~_S_lock_bit);
     475  	}
     476  
     477  #if __cpp_lib_atomic_wait
     478  	// Precondition: caller holds lock!
     479  	void
     480  	_M_wait_unlock(memory_order __o) const noexcept
     481  	{
     482  	  _GLIBCXX_TSAN_MUTEX_PRE_UNLOCK(&_M_val);
     483  	  auto __v = _M_val.fetch_sub(1, memory_order_relaxed);
     484  	  _GLIBCXX_TSAN_MUTEX_POST_UNLOCK(&_M_val);
     485  	  _M_val.wait(__v & ~_S_lock_bit, __o);
     486  	}
     487  
     488  	void
     489  	notify_one() noexcept
     490  	{
     491  	  _GLIBCXX_TSAN_MUTEX_PRE_SIGNAL(&_M_val);
     492  	  _M_val.notify_one();
     493  	  _GLIBCXX_TSAN_MUTEX_POST_SIGNAL(&_M_val);
     494  	}
     495  
     496  	void
     497  	notify_all() noexcept
     498  	{
     499  	  _GLIBCXX_TSAN_MUTEX_PRE_SIGNAL(&_M_val);
     500  	  _M_val.notify_all();
     501  	  _GLIBCXX_TSAN_MUTEX_POST_SIGNAL(&_M_val);
     502  	}
     503  #endif
     504  
     505        private:
     506  	mutable __atomic_base<uintptr_t> _M_val{0};
     507  	static constexpr uintptr_t _S_lock_bit{1};
     508        };
     509  
     510        typename _Tp::element_type* _M_ptr = nullptr;
     511        _Atomic_count _M_refcount;
     512  
     513        static typename _Atomic_count::pointer
     514        _S_add_ref(typename _Atomic_count::pointer __p)
     515        {
     516  	if (__p)
     517  	  {
     518  	    if constexpr (__is_shared_ptr<_Tp>)
     519  	      __p->_M_add_ref_copy();
     520  	    else
     521  	      __p->_M_weak_add_ref();
     522  	  }
     523  	return __p;
     524        }
     525  
     526        constexpr _Sp_atomic() noexcept = default;
     527  
     528        explicit
     529        _Sp_atomic(value_type __r) noexcept
     530        : _M_ptr(__r._M_ptr), _M_refcount(std::move(__r._M_refcount))
     531        { }
     532  
     533        ~_Sp_atomic() = default;
     534  
     535        _Sp_atomic(const _Sp_atomic&) = delete;
     536        void operator=(const _Sp_atomic&) = delete;
     537  
     538        value_type
     539        load(memory_order __o) const noexcept
     540        {
     541  	__glibcxx_assert(__o != memory_order_release
     542  			   && __o != memory_order_acq_rel);
     543  	// Ensure that the correct value of _M_ptr is visible after locking.,
     544  	// by upgrading relaxed or consume to acquire.
     545  	if (__o != memory_order_seq_cst)
     546  	  __o = memory_order_acquire;
     547  
     548  	value_type __ret;
     549  	auto __pi = _M_refcount.lock(__o);
     550  	__ret._M_ptr = _M_ptr;
     551  	__ret._M_refcount._M_pi = _S_add_ref(__pi);
     552  	_M_refcount.unlock(memory_order_relaxed);
     553  	return __ret;
     554        }
     555  
     556        void
     557        swap(value_type& __r, memory_order __o) noexcept
     558        {
     559  	_M_refcount.lock(memory_order_acquire);
     560  	std::swap(_M_ptr, __r._M_ptr);
     561  	_M_refcount._M_swap_unlock(__r._M_refcount, __o);
     562        }
     563  
     564        bool
     565        compare_exchange_strong(value_type& __expected, value_type __desired,
     566  			      memory_order __o, memory_order __o2) noexcept
     567        {
     568  	bool __result = true;
     569  	auto __pi = _M_refcount.lock(memory_order_acquire);
     570  	if (_M_ptr == __expected._M_ptr
     571  	      && __pi == __expected._M_refcount._M_pi)
     572  	  {
     573  	    _M_ptr = __desired._M_ptr;
     574  	    _M_refcount._M_swap_unlock(__desired._M_refcount, __o);
     575  	  }
     576  	else
     577  	  {
     578  	    _Tp __sink = std::move(__expected);
     579  	    __expected._M_ptr = _M_ptr;
     580  	    __expected._M_refcount._M_pi = _S_add_ref(__pi);
     581  	    _M_refcount.unlock(__o2);
     582  	    __result = false;
     583  	  }
     584  	return __result;
     585        }
     586  
     587  #if __cpp_lib_atomic_wait
     588        void
     589        wait(value_type __old, memory_order __o) const noexcept
     590        {
     591  	auto __pi = _M_refcount.lock(memory_order_acquire);
     592  	if (_M_ptr == __old._M_ptr && __pi == __old._M_refcount._M_pi)
     593  	  _M_refcount._M_wait_unlock(__o);
     594  	else
     595  	  _M_refcount.unlock(memory_order_relaxed);
     596        }
     597  
     598        void
     599        notify_one() noexcept
     600        {
     601  	_M_refcount.notify_one();
     602        }
     603  
     604        void
     605        notify_all() noexcept
     606        {
     607  	_M_refcount.notify_all();
     608        }
     609  #endif
     610      };
     611  
     612    template<typename _Tp>
     613      class atomic<shared_ptr<_Tp>>
     614      {
     615      public:
     616        using value_type = shared_ptr<_Tp>;
     617  
     618        static constexpr bool is_always_lock_free = false;
     619  
     620        bool
     621        is_lock_free() const noexcept
     622        { return false; }
     623  
     624        constexpr atomic() noexcept = default;
     625  
     626        // _GLIBCXX_RESOLVE_LIB_DEFECTS
     627        // 3661. constinit atomic<shared_ptr<T>> a(nullptr); should work
     628        constexpr atomic(nullptr_t) noexcept : atomic() { }
     629  
     630        atomic(shared_ptr<_Tp> __r) noexcept
     631        : _M_impl(std::move(__r))
     632        { }
     633  
     634        atomic(const atomic&) = delete;
     635        void operator=(const atomic&) = delete;
     636  
     637        shared_ptr<_Tp>
     638        load(memory_order __o = memory_order_seq_cst) const noexcept
     639        { return _M_impl.load(__o); }
     640  
     641        operator shared_ptr<_Tp>() const noexcept
     642        { return _M_impl.load(memory_order_seq_cst); }
     643  
     644        void
     645        store(shared_ptr<_Tp> __desired,
     646  	    memory_order __o = memory_order_seq_cst) noexcept
     647        { _M_impl.swap(__desired, __o); }
     648  
     649        void
     650        operator=(shared_ptr<_Tp> __desired) noexcept
     651        { _M_impl.swap(__desired, memory_order_seq_cst); }
     652  
     653        // _GLIBCXX_RESOLVE_LIB_DEFECTS
     654        // 3893. LWG 3661 broke atomic<shared_ptr<T>> a; a = nullptr;
     655        void
     656        operator=(nullptr_t) noexcept
     657        { store(nullptr); }
     658  
     659        shared_ptr<_Tp>
     660        exchange(shared_ptr<_Tp> __desired,
     661  	       memory_order __o = memory_order_seq_cst) noexcept
     662        {
     663  	_M_impl.swap(__desired, __o);
     664  	return __desired;
     665        }
     666  
     667        bool
     668        compare_exchange_strong(shared_ptr<_Tp>& __expected,
     669  			      shared_ptr<_Tp> __desired,
     670  			      memory_order __o, memory_order __o2) noexcept
     671        {
     672  	return _M_impl.compare_exchange_strong(__expected, __desired, __o, __o2);
     673        }
     674  
     675        bool
     676        compare_exchange_strong(value_type& __expected, value_type __desired,
     677  			      memory_order __o = memory_order_seq_cst) noexcept
     678        {
     679  	memory_order __o2;
     680  	switch (__o)
     681  	{
     682  	case memory_order_acq_rel:
     683  	  __o2 = memory_order_acquire;
     684  	  break;
     685  	case memory_order_release:
     686  	  __o2 = memory_order_relaxed;
     687  	  break;
     688  	default:
     689  	  __o2 = __o;
     690  	}
     691  	return compare_exchange_strong(__expected, std::move(__desired),
     692  				       __o, __o2);
     693        }
     694  
     695        bool
     696        compare_exchange_weak(value_type& __expected, value_type __desired,
     697  			    memory_order __o, memory_order __o2) noexcept
     698        {
     699  	return compare_exchange_strong(__expected, std::move(__desired),
     700  				       __o, __o2);
     701        }
     702  
     703        bool
     704        compare_exchange_weak(value_type& __expected, value_type __desired,
     705  			    memory_order __o = memory_order_seq_cst) noexcept
     706        {
     707  	return compare_exchange_strong(__expected, std::move(__desired), __o);
     708        }
     709  
     710  #if __cpp_lib_atomic_wait
     711        void
     712        wait(value_type __old,
     713  	   memory_order __o = memory_order_seq_cst) const noexcept
     714        {
     715  	_M_impl.wait(std::move(__old), __o);
     716        }
     717  
     718        void
     719        notify_one() noexcept
     720        {
     721  	_M_impl.notify_one();
     722        }
     723  
     724        void
     725        notify_all() noexcept
     726        {
     727  	_M_impl.notify_all();
     728        }
     729  #endif
     730  
     731      private:
     732        _Sp_atomic<shared_ptr<_Tp>> _M_impl;
     733      };
     734  
     735    template<typename _Tp>
     736      class atomic<weak_ptr<_Tp>>
     737      {
     738      public:
     739        using value_type = weak_ptr<_Tp>;
     740  
     741        static constexpr bool is_always_lock_free = false;
     742  
     743        bool
     744        is_lock_free() const noexcept
     745        { return false; }
     746  
     747        constexpr atomic() noexcept = default;
     748  
     749        atomic(weak_ptr<_Tp> __r) noexcept
     750       : _M_impl(move(__r))
     751        { }
     752  
     753        atomic(const atomic&) = delete;
     754        void operator=(const atomic&) = delete;
     755  
     756        weak_ptr<_Tp>
     757        load(memory_order __o = memory_order_seq_cst) const noexcept
     758        { return _M_impl.load(__o); }
     759  
     760        operator weak_ptr<_Tp>() const noexcept
     761        { return _M_impl.load(memory_order_seq_cst); }
     762  
     763        void
     764        store(weak_ptr<_Tp> __desired,
     765  	    memory_order __o = memory_order_seq_cst) noexcept
     766        { _M_impl.swap(__desired, __o); }
     767  
     768        void
     769        operator=(weak_ptr<_Tp> __desired) noexcept
     770        { _M_impl.swap(__desired, memory_order_seq_cst); }
     771  
     772        weak_ptr<_Tp>
     773        exchange(weak_ptr<_Tp> __desired,
     774  	       memory_order __o = memory_order_seq_cst) noexcept
     775        {
     776  	_M_impl.swap(__desired, __o);
     777  	return __desired;
     778        }
     779  
     780        bool
     781        compare_exchange_strong(weak_ptr<_Tp>& __expected,
     782  			      weak_ptr<_Tp> __desired,
     783  			      memory_order __o, memory_order __o2) noexcept
     784        {
     785  	return _M_impl.compare_exchange_strong(__expected, __desired, __o, __o2);
     786        }
     787  
     788        bool
     789        compare_exchange_strong(value_type& __expected, value_type __desired,
     790  			      memory_order __o = memory_order_seq_cst) noexcept
     791        {
     792  	memory_order __o2;
     793  	switch (__o)
     794  	{
     795  	case memory_order_acq_rel:
     796  	  __o2 = memory_order_acquire;
     797  	  break;
     798  	case memory_order_release:
     799  	  __o2 = memory_order_relaxed;
     800  	  break;
     801  	default:
     802  	  __o2 = __o;
     803  	}
     804  	return compare_exchange_strong(__expected, std::move(__desired),
     805  				       __o, __o2);
     806        }
     807  
     808        bool
     809        compare_exchange_weak(value_type& __expected, value_type __desired,
     810  			    memory_order __o, memory_order __o2) noexcept
     811        {
     812  	return compare_exchange_strong(__expected, std::move(__desired),
     813  				       __o, __o2);
     814        }
     815  
     816        bool
     817        compare_exchange_weak(value_type& __expected, value_type __desired,
     818  			    memory_order __o = memory_order_seq_cst) noexcept
     819        {
     820  	return compare_exchange_strong(__expected, std::move(__desired), __o);
     821        }
     822  
     823  #if __cpp_lib_atomic_wait
     824        void
     825        wait(value_type __old,
     826  	   memory_order __o = memory_order_seq_cst) const noexcept
     827        {
     828  	_M_impl.wait(std::move(__old), __o);
     829        }
     830  
     831        void
     832        notify_one() noexcept
     833        {
     834  	_M_impl.notify_one();
     835        }
     836  
     837        void
     838        notify_all() noexcept
     839        {
     840  	_M_impl.notify_all();
     841        }
     842  #endif
     843  
     844      private:
     845        _Sp_atomic<weak_ptr<_Tp>> _M_impl;
     846      };
     847    /// @} group pointer_abstractions
     848  #endif // C++20
     849  
     850  _GLIBCXX_END_NAMESPACE_VERSION
     851  } // namespace
     852  
     853  #endif // _SHARED_PTR_ATOMIC_H