1 // shared_ptr atomic access -*- C++ -*-
2 
3 // Copyright (C) 2014-2022 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 
_GLIBCXX_VISIBILITY(default)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     struct 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 struct 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     struct 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     struct 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
854