xref: /netbsd-src/external/gpl3/gcc/dist/libstdc++-v3/include/bits/shared_ptr_atomic.h (revision c42dbd0ed2e61fe6eda8590caa852ccf34719964)
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 
61 namespace std _GLIBCXX_VISIBILITY(default)
62 {
63 _GLIBCXX_BEGIN_NAMESPACE_VERSION
64 
65   /**
66    * @addtogroup pointer_abstractions
67    * @{
68    */
69   /// @relates shared_ptr @{
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 @c memory_order_release or
124    *  @c 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 @c memory_order_acquire or
160    *  @c 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 @c *__p.
197    *  @return The original value of @c *__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 @c *__p was equivalent to @c *__v, false otherwise.
244    *
245    *  The memory order for failure shall not be @c memory_order_release or
246    *  @c memory_order_acq_rel, or stronger than the memory order for success.
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 #if __cplusplus >= 202002L
357 # define __cpp_lib_atomic_shared_ptr 201711L
358   template<typename _Tp>
359     class atomic;
360 
361   template<typename _Up>
362     static constexpr bool __is_shared_ptr = false;
363   template<typename _Up>
364     static constexpr bool __is_shared_ptr<shared_ptr<_Up>> = true;
365 
366   template<typename _Tp>
367     class _Sp_atomic
368     {
369       using value_type = _Tp;
370 
371       friend class atomic<_Tp>;
372 
373       // An atomic version of __shared_count<> and __weak_count<>.
374       // Stores a _Sp_counted_base<>* but uses the LSB as a lock.
375       struct _Atomic_count
376       {
377 	// Either __shared_count<> or __weak_count<>
378 	using __count_type = decltype(_Tp::_M_refcount);
379 
380 	// _Sp_counted_base<>*
381 	using pointer = decltype(__count_type::_M_pi);
382 
383 	// Ensure we can use the LSB as the lock bit.
384 	static_assert(alignof(remove_pointer_t<pointer>) > 1);
385 
386 	constexpr _Atomic_count() noexcept = default;
387 
388 	explicit
389 	_Atomic_count(__count_type&& __c) noexcept
390 	: _M_val(reinterpret_cast<uintptr_t>(__c._M_pi))
391 	{
392 	  __c._M_pi = nullptr;
393 	}
394 
395 	~_Atomic_count()
396 	{
397 	  auto __val = _M_val.load(memory_order_relaxed);
398 	  _GLIBCXX_TSAN_MUTEX_DESTROY(&_M_val);
399 	  __glibcxx_assert(!(__val & _S_lock_bit));
400 	  if (auto __pi = reinterpret_cast<pointer>(__val))
401 	    {
402 	      if constexpr (__is_shared_ptr<_Tp>)
403 		__pi->_M_release();
404 	      else
405 		__pi->_M_weak_release();
406 	    }
407 	}
408 
409 	_Atomic_count(const _Atomic_count&) = delete;
410 	_Atomic_count& operator=(const _Atomic_count&) = delete;
411 
412 	// Precondition: Caller does not hold lock!
413 	// Returns the raw pointer value without the lock bit set.
414 	pointer
415 	lock(memory_order __o) const noexcept
416 	{
417 	  // To acquire the lock we flip the LSB from 0 to 1.
418 
419 	  auto __current = _M_val.load(memory_order_relaxed);
420 	  while (__current & _S_lock_bit)
421 	    {
422 #if __cpp_lib_atomic_wait
423 	      __detail::__thread_relax();
424 #endif
425 	      __current = _M_val.load(memory_order_relaxed);
426 	    }
427 
428 	  _GLIBCXX_TSAN_MUTEX_TRY_LOCK(&_M_val);
429 
430 	  while (!_M_val.compare_exchange_strong(__current,
431 						 __current | _S_lock_bit,
432 						 __o,
433 						 memory_order_relaxed))
434 	    {
435 	      _GLIBCXX_TSAN_MUTEX_TRY_LOCK_FAILED(&_M_val);
436 #if __cpp_lib_atomic_wait
437 	      __detail::__thread_relax();
438 #endif
439 	      __current = __current & ~_S_lock_bit;
440 	      _GLIBCXX_TSAN_MUTEX_TRY_LOCK(&_M_val);
441 	    }
442 	  _GLIBCXX_TSAN_MUTEX_LOCKED(&_M_val);
443 	  return reinterpret_cast<pointer>(__current);
444 	}
445 
446 	// Precondition: caller holds lock!
447 	void
448 	unlock(memory_order __o) const noexcept
449 	{
450 	  _GLIBCXX_TSAN_MUTEX_PRE_UNLOCK(&_M_val);
451 	  _M_val.fetch_sub(1, __o);
452 	  _GLIBCXX_TSAN_MUTEX_POST_UNLOCK(&_M_val);
453 	}
454 
455 	// Swaps the values of *this and __c, and unlocks *this.
456 	// Precondition: caller holds lock!
457 	void
458 	_M_swap_unlock(__count_type& __c, memory_order __o) noexcept
459 	{
460 	  if (__o != memory_order_seq_cst)
461 	    __o = memory_order_release;
462 	  auto __x = reinterpret_cast<uintptr_t>(__c._M_pi);
463 	  _GLIBCXX_TSAN_MUTEX_PRE_UNLOCK(&_M_val);
464 	  __x = _M_val.exchange(__x, __o);
465 	  _GLIBCXX_TSAN_MUTEX_POST_UNLOCK(&_M_val);
466 	  __c._M_pi = reinterpret_cast<pointer>(__x & ~_S_lock_bit);
467 	}
468 
469 #if __cpp_lib_atomic_wait
470 	// Precondition: caller holds lock!
471 	void
472 	_M_wait_unlock(memory_order __o) const noexcept
473 	{
474 	  _GLIBCXX_TSAN_MUTEX_PRE_UNLOCK(&_M_val);
475 	  auto __v = _M_val.fetch_sub(1, memory_order_relaxed);
476 	  _GLIBCXX_TSAN_MUTEX_POST_UNLOCK(&_M_val);
477 	  _M_val.wait(__v & ~_S_lock_bit, __o);
478 	}
479 
480 	void
481 	notify_one() noexcept
482 	{
483 	  _GLIBCXX_TSAN_MUTEX_PRE_SIGNAL(&_M_val);
484 	  _M_val.notify_one();
485 	  _GLIBCXX_TSAN_MUTEX_POST_SIGNAL(&_M_val);
486 	}
487 
488 	void
489 	notify_all() noexcept
490 	{
491 	  _GLIBCXX_TSAN_MUTEX_PRE_SIGNAL(&_M_val);
492 	  _M_val.notify_all();
493 	  _GLIBCXX_TSAN_MUTEX_POST_SIGNAL(&_M_val);
494 	}
495 #endif
496 
497       private:
498 	mutable __atomic_base<uintptr_t> _M_val{0};
499 	static constexpr uintptr_t _S_lock_bit{1};
500       };
501 
502       typename _Tp::element_type* _M_ptr = nullptr;
503       _Atomic_count _M_refcount;
504 
505       static typename _Atomic_count::pointer
506       _S_add_ref(typename _Atomic_count::pointer __p)
507       {
508 	if (__p)
509 	  {
510 	    if constexpr (__is_shared_ptr<_Tp>)
511 	      __p->_M_add_ref_copy();
512 	    else
513 	      __p->_M_weak_add_ref();
514 	  }
515 	return __p;
516       }
517 
518       constexpr _Sp_atomic() noexcept = default;
519 
520       explicit
521       _Sp_atomic(value_type __r) noexcept
522       : _M_ptr(__r._M_ptr), _M_refcount(std::move(__r._M_refcount))
523       { }
524 
525       ~_Sp_atomic() = default;
526 
527       _Sp_atomic(const _Sp_atomic&) = delete;
528       void operator=(const _Sp_atomic&) = delete;
529 
530       value_type
531       load(memory_order __o) const noexcept
532       {
533 	__glibcxx_assert(__o != memory_order_release
534 			   && __o != memory_order_acq_rel);
535 	// Ensure that the correct value of _M_ptr is visible after locking.,
536 	// by upgrading relaxed or consume to acquire.
537 	if (__o != memory_order_seq_cst)
538 	  __o = memory_order_acquire;
539 
540 	value_type __ret;
541 	auto __pi = _M_refcount.lock(__o);
542 	__ret._M_ptr = _M_ptr;
543 	__ret._M_refcount._M_pi = _S_add_ref(__pi);
544 	_M_refcount.unlock(memory_order_relaxed);
545 	return __ret;
546       }
547 
548       void
549       swap(value_type& __r, memory_order __o) noexcept
550       {
551 	_M_refcount.lock(memory_order_acquire);
552 	std::swap(_M_ptr, __r._M_ptr);
553 	_M_refcount._M_swap_unlock(__r._M_refcount, __o);
554       }
555 
556       bool
557       compare_exchange_strong(value_type& __expected, value_type __desired,
558 			      memory_order __o, memory_order __o2) noexcept
559       {
560 	bool __result = true;
561 	auto __pi = _M_refcount.lock(memory_order_acquire);
562 	if (_M_ptr == __expected._M_ptr
563 	      && __pi == __expected._M_refcount._M_pi)
564 	  {
565 	    _M_ptr = __desired._M_ptr;
566 	    _M_refcount._M_swap_unlock(__desired._M_refcount, __o);
567 	  }
568 	else
569 	  {
570 	    _Tp __sink = std::move(__expected);
571 	    __expected._M_ptr = _M_ptr;
572 	    __expected._M_refcount._M_pi = _S_add_ref(__pi);
573 	    _M_refcount.unlock(__o2);
574 	    __result = false;
575 	  }
576 	return __result;
577       }
578 
579 #if __cpp_lib_atomic_wait
580       void
581       wait(value_type __old, memory_order __o) const noexcept
582       {
583 	auto __pi = _M_refcount.lock(memory_order_acquire);
584 	if (_M_ptr == __old._M_ptr && __pi == __old._M_refcount._M_pi)
585 	  _M_refcount._M_wait_unlock(__o);
586 	else
587 	  _M_refcount.unlock(memory_order_relaxed);
588       }
589 
590       void
591       notify_one() noexcept
592       {
593 	_M_refcount.notify_one();
594       }
595 
596       void
597       notify_all() noexcept
598       {
599 	_M_refcount.notify_all();
600       }
601 #endif
602     };
603 
604   template<typename _Tp>
605     class atomic<shared_ptr<_Tp>>
606     {
607     public:
608       using value_type = shared_ptr<_Tp>;
609 
610       static constexpr bool is_always_lock_free = false;
611 
612       bool
613       is_lock_free() const noexcept
614       { return false; }
615 
616       constexpr atomic() noexcept = default;
617 
618       // _GLIBCXX_RESOLVE_LIB_DEFECTS
619       // 3661. constinit atomic<shared_ptr<T>> a(nullptr); should work
620       constexpr atomic(nullptr_t) noexcept : atomic() { }
621 
622       atomic(shared_ptr<_Tp> __r) noexcept
623       : _M_impl(std::move(__r))
624       { }
625 
626       atomic(const atomic&) = delete;
627       void operator=(const atomic&) = delete;
628 
629       shared_ptr<_Tp>
630       load(memory_order __o = memory_order_seq_cst) const noexcept
631       { return _M_impl.load(__o); }
632 
633       operator shared_ptr<_Tp>() const noexcept
634       { return _M_impl.load(memory_order_seq_cst); }
635 
636       void
637       store(shared_ptr<_Tp> __desired,
638 	    memory_order __o = memory_order_seq_cst) noexcept
639       { _M_impl.swap(__desired, __o); }
640 
641       void
642       operator=(shared_ptr<_Tp> __desired) noexcept
643       { _M_impl.swap(__desired, memory_order_seq_cst); }
644 
645       // _GLIBCXX_RESOLVE_LIB_DEFECTS
646       // 3893. LWG 3661 broke atomic<shared_ptr<T>> a; a = nullptr;
647       void
648       operator=(nullptr_t) noexcept
649       { store(nullptr); }
650 
651       shared_ptr<_Tp>
652       exchange(shared_ptr<_Tp> __desired,
653 	       memory_order __o = memory_order_seq_cst) noexcept
654       {
655 	_M_impl.swap(__desired, __o);
656 	return __desired;
657       }
658 
659       bool
660       compare_exchange_strong(shared_ptr<_Tp>& __expected,
661 			      shared_ptr<_Tp> __desired,
662 			      memory_order __o, memory_order __o2) noexcept
663       {
664 	return _M_impl.compare_exchange_strong(__expected, __desired, __o, __o2);
665       }
666 
667       bool
668       compare_exchange_strong(value_type& __expected, value_type __desired,
669 			      memory_order __o = memory_order_seq_cst) noexcept
670       {
671 	memory_order __o2;
672 	switch (__o)
673 	{
674 	case memory_order_acq_rel:
675 	  __o2 = memory_order_acquire;
676 	  break;
677 	case memory_order_release:
678 	  __o2 = memory_order_relaxed;
679 	  break;
680 	default:
681 	  __o2 = __o;
682 	}
683 	return compare_exchange_strong(__expected, std::move(__desired),
684 				       __o, __o2);
685       }
686 
687       bool
688       compare_exchange_weak(value_type& __expected, value_type __desired,
689 			    memory_order __o, memory_order __o2) noexcept
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_seq_cst) noexcept
698       {
699 	return compare_exchange_strong(__expected, std::move(__desired), __o);
700       }
701 
702 #if __cpp_lib_atomic_wait
703       void
704       wait(value_type __old,
705 	   memory_order __o = memory_order_seq_cst) const noexcept
706       {
707 	_M_impl.wait(std::move(__old), __o);
708       }
709 
710       void
711       notify_one() noexcept
712       {
713 	_M_impl.notify_one();
714       }
715 
716       void
717       notify_all() noexcept
718       {
719 	_M_impl.notify_all();
720       }
721 #endif
722 
723     private:
724       _Sp_atomic<shared_ptr<_Tp>> _M_impl;
725     };
726 
727   template<typename _Tp>
728     class atomic<weak_ptr<_Tp>>
729     {
730     public:
731       using value_type = weak_ptr<_Tp>;
732 
733       static constexpr bool is_always_lock_free = false;
734 
735       bool
736       is_lock_free() const noexcept
737       { return false; }
738 
739       constexpr atomic() noexcept = default;
740 
741       atomic(weak_ptr<_Tp> __r) noexcept
742      : _M_impl(move(__r))
743       { }
744 
745       atomic(const atomic&) = delete;
746       void operator=(const atomic&) = delete;
747 
748       weak_ptr<_Tp>
749       load(memory_order __o = memory_order_seq_cst) const noexcept
750       { return _M_impl.load(__o); }
751 
752       operator weak_ptr<_Tp>() const noexcept
753       { return _M_impl.load(memory_order_seq_cst); }
754 
755       void
756       store(weak_ptr<_Tp> __desired,
757 	    memory_order __o = memory_order_seq_cst) noexcept
758       { _M_impl.swap(__desired, __o); }
759 
760       void
761       operator=(weak_ptr<_Tp> __desired) noexcept
762       { _M_impl.swap(__desired, memory_order_seq_cst); }
763 
764       weak_ptr<_Tp>
765       exchange(weak_ptr<_Tp> __desired,
766 	       memory_order __o = memory_order_seq_cst) noexcept
767       {
768 	_M_impl.swap(__desired, __o);
769 	return __desired;
770       }
771 
772       bool
773       compare_exchange_strong(weak_ptr<_Tp>& __expected,
774 			      weak_ptr<_Tp> __desired,
775 			      memory_order __o, memory_order __o2) noexcept
776       {
777 	return _M_impl.compare_exchange_strong(__expected, __desired, __o, __o2);
778       }
779 
780       bool
781       compare_exchange_strong(value_type& __expected, value_type __desired,
782 			      memory_order __o = memory_order_seq_cst) noexcept
783       {
784 	memory_order __o2;
785 	switch (__o)
786 	{
787 	case memory_order_acq_rel:
788 	  __o2 = memory_order_acquire;
789 	  break;
790 	case memory_order_release:
791 	  __o2 = memory_order_relaxed;
792 	  break;
793 	default:
794 	  __o2 = __o;
795 	}
796 	return compare_exchange_strong(__expected, std::move(__desired),
797 				       __o, __o2);
798       }
799 
800       bool
801       compare_exchange_weak(value_type& __expected, value_type __desired,
802 			    memory_order __o, memory_order __o2) noexcept
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_seq_cst) noexcept
811       {
812 	return compare_exchange_strong(__expected, std::move(__desired), __o);
813       }
814 
815 #if __cpp_lib_atomic_wait
816       void
817       wait(value_type __old,
818 	   memory_order __o = memory_order_seq_cst) const noexcept
819       {
820 	_M_impl.wait(std::move(__old), __o);
821       }
822 
823       void
824       notify_one() noexcept
825       {
826 	_M_impl.notify_one();
827       }
828 
829       void
830       notify_all() noexcept
831       {
832 	_M_impl.notify_all();
833       }
834 #endif
835 
836     private:
837       _Sp_atomic<weak_ptr<_Tp>> _M_impl;
838     };
839 #endif // C++20
840 
841   /// @} relates shared_ptr
842   /// @} group pointer_abstractions
843 
844 _GLIBCXX_END_NAMESPACE_VERSION
845 } // namespace
846 
847 #endif // _SHARED_PTR_ATOMIC_H
848