1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef _LIBCPP___MEMORY_SHARED_COUNT_H
10#define _LIBCPP___MEMORY_SHARED_COUNT_H
11
12#include <__config>
13#include <__memory/addressof.h>
14#include <typeinfo>
15
16#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
17# pragma GCC system_header
18#endif
19
20_LIBCPP_BEGIN_NAMESPACE_STD
21
22// NOTE: Relaxed and acq/rel atomics (for increment and decrement respectively)
23// should be sufficient for thread safety.
24// See https://llvm.org/PR22803
25#if (defined(__clang__) && __has_builtin(__atomic_add_fetch) && defined(__ATOMIC_RELAXED) && \
26 defined(__ATOMIC_ACQ_REL)) || \
27 defined(_LIBCPP_COMPILER_GCC)
28# define _LIBCPP_HAS_BUILTIN_ATOMIC_SUPPORT 1
29#else
30# define _LIBCPP_HAS_BUILTIN_ATOMIC_SUPPORT 0
31#endif
32
33template <class _ValueType>
34inline _LIBCPP_HIDE_FROM_ABI _ValueType __libcpp_relaxed_load(_ValueType const* __value) {
35#if _LIBCPP_HAS_THREADS && defined(__ATOMIC_RELAXED) && \
36 (__has_builtin(__atomic_load_n) || defined(_LIBCPP_COMPILER_GCC))
37 return __atomic_load_n(__value, __ATOMIC_RELAXED);
38#else
39 return *__value;
40#endif
41}
42
43template <class _ValueType>
44inline _LIBCPP_HIDE_FROM_ABI _ValueType __libcpp_acquire_load(_ValueType const* __value) {
45#if _LIBCPP_HAS_THREADS && defined(__ATOMIC_ACQUIRE) && \
46 (__has_builtin(__atomic_load_n) || defined(_LIBCPP_COMPILER_GCC))
47 return __atomic_load_n(__value, __ATOMIC_ACQUIRE);
48#else
49 return *__value;
50#endif
51}
52
53template <class _Tp>
54inline _LIBCPP_HIDE_FROM_ABI _Tp __libcpp_atomic_refcount_increment(_Tp& __t) _NOEXCEPT {
55#if _LIBCPP_HAS_BUILTIN_ATOMIC_SUPPORT && _LIBCPP_HAS_THREADS
56 return __atomic_add_fetch(std::addressof(__t), 1, __ATOMIC_RELAXED);
57#else
58 return __t += 1;
59#endif
60}
61
62template <class _Tp>
63inline _LIBCPP_HIDE_FROM_ABI _Tp __libcpp_atomic_refcount_decrement(_Tp& __t) _NOEXCEPT {
64#if _LIBCPP_HAS_BUILTIN_ATOMIC_SUPPORT && _LIBCPP_HAS_THREADS
65 return __atomic_add_fetch(std::addressof(__t), -1, __ATOMIC_ACQ_REL);
66#else
67 return __t -= 1;
68#endif
69}
70
71class _LIBCPP_EXPORTED_FROM_ABI __shared_count {
72 __shared_count(const __shared_count&);
73 __shared_count& operator=(const __shared_count&);
74
75protected:
76 long __shared_owners_;
77 virtual ~__shared_count();
78
79private:
80 virtual void __on_zero_shared() _NOEXCEPT = 0;
81
82public:
83 _LIBCPP_HIDE_FROM_ABI explicit __shared_count(long __refs = 0) _NOEXCEPT : __shared_owners_(__refs) {}
84
85#if defined(_LIBCPP_SHARED_PTR_DEFINE_LEGACY_INLINE_FUNCTIONS)
86 void __add_shared() noexcept;
87 bool __release_shared() noexcept;
88#else
89 _LIBCPP_HIDE_FROM_ABI void __add_shared() _NOEXCEPT { __libcpp_atomic_refcount_increment(t&: __shared_owners_); }
90 _LIBCPP_HIDE_FROM_ABI bool __release_shared() _NOEXCEPT {
91 if (__libcpp_atomic_refcount_decrement(t&: __shared_owners_) == -1) {
92 __on_zero_shared();
93 return true;
94 }
95 return false;
96 }
97#endif
98 _LIBCPP_HIDE_FROM_ABI long use_count() const _NOEXCEPT { return __libcpp_relaxed_load(value: &__shared_owners_) + 1; }
99};
100
101class _LIBCPP_EXPORTED_FROM_ABI __shared_weak_count : private __shared_count {
102 long __shared_weak_owners_;
103
104public:
105 _LIBCPP_HIDE_FROM_ABI explicit __shared_weak_count(long __refs = 0) _NOEXCEPT
106 : __shared_count(__refs),
107 __shared_weak_owners_(__refs) {}
108
109protected:
110 ~__shared_weak_count() override;
111
112public:
113#if defined(_LIBCPP_SHARED_PTR_DEFINE_LEGACY_INLINE_FUNCTIONS)
114 void __add_shared() noexcept;
115 void __add_weak() noexcept;
116 void __release_shared() noexcept;
117#else
118 _LIBCPP_HIDE_FROM_ABI void __add_shared() _NOEXCEPT { __shared_count::__add_shared(); }
119 _LIBCPP_HIDE_FROM_ABI void __add_weak() _NOEXCEPT { __libcpp_atomic_refcount_increment(t&: __shared_weak_owners_); }
120 _LIBCPP_HIDE_FROM_ABI void __release_shared() _NOEXCEPT {
121 if (__shared_count::__release_shared())
122 __release_weak();
123 }
124#endif
125 void __release_weak() _NOEXCEPT;
126 _LIBCPP_HIDE_FROM_ABI long use_count() const _NOEXCEPT { return __shared_count::use_count(); }
127 __shared_weak_count* lock() _NOEXCEPT;
128
129 virtual const void* __get_deleter(const type_info&) const _NOEXCEPT;
130
131private:
132 virtual void __on_zero_shared_weak() _NOEXCEPT = 0;
133};
134
135_LIBCPP_END_NAMESPACE_STD
136
137#endif // _LIBCPP___MEMORY_SHARED_COUNT_H
138