libstdc++
shared_ptr_atomic.h
Go to the documentation of this file.
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};
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  {
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  {
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  {
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};
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  {
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  {
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  {
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
__shared_ptr< _Tp, _Lp > atomic_load_explicit(const __shared_ptr< _Tp, _Lp > *__p, memory_order)
Atomic load for shared_ptr objects.
memory_order
Enumeration for memory_order.
Definition: atomic_base.h:62
bool atomic_compare_exchange_weak_explicit(__shared_ptr< _Tp, _Lp > *__p, __shared_ptr< _Tp, _Lp > *__v, __shared_ptr< _Tp, _Lp > __w, memory_order __success, memory_order __failure)
Atomic compare-and-swap for shared_ptr objects.
bool atomic_compare_exchange_strong_explicit(__shared_ptr< _Tp, _Lp > *__p, __shared_ptr< _Tp, _Lp > *__v, __shared_ptr< _Tp, _Lp > __w, memory_order, memory_order)
Atomic compare-and-swap for shared_ptr objects.
void atomic_store_explicit(__shared_ptr< _Tp, _Lp > *__p, __shared_ptr< _Tp, _Lp > __r, memory_order)
Atomic store for shared_ptr objects.
void swap(shared_ptr< _Tp > &__a, shared_ptr< _Tp > &__b) noexcept
Swap overload for shared_ptr.
ISO C++ entities toplevel namespace is std.
__shared_ptr< _Tp, _Lp > atomic_exchange_explicit(__shared_ptr< _Tp, _Lp > *__p, __shared_ptr< _Tp, _Lp > __r, memory_order)
Atomic exchange for shared_ptr objects.
void lock(_L1 &__l1, _L2 &__l2, _L3 &... __l3)
Generic lock.
Definition: mutex:693
A smart pointer with reference-counted copy semantics.
Primary template owner_less.
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition: move.h:97