1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef PARTITION_ALLOC_PARTITION_ALLOC_BASE_MEMORY_REF_COUNTED_H_
6 #define PARTITION_ALLOC_PARTITION_ALLOC_BASE_MEMORY_REF_COUNTED_H_
7 
8 #include "build/build_config.h"
9 #include "partition_alloc/partition_alloc_base/atomic_ref_count.h"
10 #include "partition_alloc/partition_alloc_base/check.h"
11 #include "partition_alloc/partition_alloc_base/compiler_specific.h"
12 #include "partition_alloc/partition_alloc_base/component_export.h"
13 #include "partition_alloc/partition_alloc_base/debug/debugging_buildflags.h"
14 #include "partition_alloc/partition_alloc_base/memory/scoped_refptr.h"
15 
16 namespace partition_alloc::internal::base {
17 namespace subtle {
18 
PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE)19 class PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE) RefCountedThreadSafeBase {
20  public:
21   RefCountedThreadSafeBase(const RefCountedThreadSafeBase&) = delete;
22   RefCountedThreadSafeBase& operator=(const RefCountedThreadSafeBase&) = delete;
23 
24   bool HasOneRef() const;
25   bool HasAtLeastOneRef() const;
26 
27  protected:
28   explicit constexpr RefCountedThreadSafeBase(StartRefCountFromZeroTag) {}
29   explicit constexpr RefCountedThreadSafeBase(StartRefCountFromOneTag)
30       : ref_count_(1) {
31 #if BUILDFLAG(PA_DCHECK_IS_ON)
32     needs_adopt_ref_ = true;
33 #endif
34   }
35 
36 #if BUILDFLAG(PA_DCHECK_IS_ON)
37   ~RefCountedThreadSafeBase();
38 #else
39   ~RefCountedThreadSafeBase() = default;
40 #endif
41 
42 // Release and AddRef are suitable for inlining on X86 because they generate
43 // very small code sequences. On other platforms (ARM), it causes a size
44 // regression and is probably not worth it.
45 #if defined(ARCH_CPU_X86_FAMILY)
46   // Returns true if the object should self-delete.
47   bool Release() const { return ReleaseImpl(); }
48   void AddRef() const { AddRefImpl(); }
49   void AddRefWithCheck() const { AddRefWithCheckImpl(); }
50 #else
51   // Returns true if the object should self-delete.
52   bool Release() const;
53   void AddRef() const;
54   void AddRefWithCheck() const;
55 #endif
56 
57  private:
58   template <typename U>
59   friend scoped_refptr<U> AdoptRef(U*);
60 
61   void Adopted() const {
62 #if BUILDFLAG(PA_DCHECK_IS_ON)
63     PA_BASE_DCHECK(needs_adopt_ref_);
64     needs_adopt_ref_ = false;
65 #endif
66   }
67 
68   PA_ALWAYS_INLINE void AddRefImpl() const {
69 #if BUILDFLAG(PA_DCHECK_IS_ON)
70     PA_BASE_DCHECK(!in_dtor_);
71     // This RefCounted object is created with non-zero reference count.
72     // The first reference to such a object has to be made by AdoptRef or
73     // MakeRefCounted.
74     PA_BASE_DCHECK(!needs_adopt_ref_);
75 #endif
76     ref_count_.Increment();
77   }
78 
79   PA_ALWAYS_INLINE void AddRefWithCheckImpl() const {
80 #if BUILDFLAG(PA_DCHECK_IS_ON)
81     PA_BASE_DCHECK(!in_dtor_);
82     // This RefCounted object is created with non-zero reference count.
83     // The first reference to such a object has to be made by AdoptRef or
84     // MakeRefCounted.
85     PA_BASE_DCHECK(!needs_adopt_ref_);
86 #endif
87     PA_BASE_CHECK(ref_count_.Increment() > 0);
88   }
89 
90   PA_ALWAYS_INLINE bool ReleaseImpl() const {
91 #if BUILDFLAG(PA_DCHECK_IS_ON)
92     PA_BASE_DCHECK(!in_dtor_);
93     PA_BASE_DCHECK(!ref_count_.IsZero());
94 #endif
95     if (!ref_count_.Decrement()) {
96 #if BUILDFLAG(PA_DCHECK_IS_ON)
97       in_dtor_ = true;
98 #endif
99       return true;
100     }
101     return false;
102   }
103 
104   mutable AtomicRefCount ref_count_{0};
105 #if BUILDFLAG(PA_DCHECK_IS_ON)
106   mutable bool needs_adopt_ref_ = false;
107   mutable bool in_dtor_ = false;
108 #endif
109 };
110 
111 }  // namespace subtle
112 
113 // Forward declaration.
114 template <class T, typename Traits>
115 class RefCountedThreadSafe;
116 
117 // Default traits for RefCountedThreadSafe<T>.  Deletes the object when its ref
118 // count reaches 0.  Overload to delete it on a different thread etc.
119 template <typename T>
120 struct DefaultRefCountedThreadSafeTraits {
DestructDefaultRefCountedThreadSafeTraits121   static void Destruct(const T* x) {
122     // Delete through RefCountedThreadSafe to make child classes only need to be
123     // friend with RefCountedThreadSafe instead of this struct, which is an
124     // implementation detail.
125     RefCountedThreadSafe<T, DefaultRefCountedThreadSafeTraits>::DeleteInternal(
126         x);
127   }
128 };
129 
130 //
131 // A thread-safe variant of RefCounted<T>
132 //
133 //   class MyFoo : public base::RefCountedThreadSafe<MyFoo> {
134 //    ...
135 //   };
136 //
137 // If you're using the default trait, then you should add compile time
138 // asserts that no one else is deleting your object.  i.e.
139 //    private:
140 //     friend class base::RefCountedThreadSafe<MyFoo>;
141 //     ~MyFoo();
142 //
143 // We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe
144 // too. See the comment above the RefCounted definition for details.
145 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T>>
146 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
147  public:
148   static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference =
149       subtle::kStartRefCountFromZeroTag;
150 
RefCountedThreadSafe()151   explicit RefCountedThreadSafe()
152       : subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {}
153 
154   RefCountedThreadSafe(const RefCountedThreadSafe&) = delete;
155   RefCountedThreadSafe& operator=(const RefCountedThreadSafe&) = delete;
156 
AddRef()157   void AddRef() const { AddRefImpl(T::kRefCountPreference); }
158 
Release()159   void Release() const {
160     if (subtle::RefCountedThreadSafeBase::Release()) {
161       PA_ANALYZER_SKIP_THIS_PATH();
162       Traits::Destruct(static_cast<const T*>(this));
163     }
164   }
165 
166  protected:
167   ~RefCountedThreadSafe() = default;
168 
169  private:
170   friend struct DefaultRefCountedThreadSafeTraits<T>;
171   template <typename U>
172   static void DeleteInternal(const U* x) {
173     delete x;
174   }
175 
176   void AddRefImpl(subtle::StartRefCountFromZeroTag) const {
177     subtle::RefCountedThreadSafeBase::AddRef();
178   }
179 
180   void AddRefImpl(subtle::StartRefCountFromOneTag) const {
181     subtle::RefCountedThreadSafeBase::AddRefWithCheck();
182   }
183 };
184 
185 }  // namespace partition_alloc::internal::base
186 
187 #endif  // PARTITION_ALLOC_PARTITION_ALLOC_BASE_MEMORY_REF_COUNTED_H_
188