1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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 BASE_MEMORY_REF_COUNTED_H_
6 #define BASE_MEMORY_REF_COUNTED_H_
7 
8 #include <stddef.h>
9 
10 #include <utility>
11 
12 #include "base/atomic_ref_count.h"
13 #include "base/compiler_specific.h"
14 #include "base/logging.h"
15 #include "base/macros.h"
16 #include "base/memory/scoped_refptr.h"
17 #include "util/build_config.h"
18 
19 namespace base {
20 namespace subtle {
21 
22 class RefCountedBase {
23  public:
HasOneRef()24   bool HasOneRef() const { return ref_count_ == 1; }
25 
26  protected:
RefCountedBase(StartRefCountFromZeroTag)27   explicit RefCountedBase(StartRefCountFromZeroTag) {}
28 
RefCountedBase(StartRefCountFromOneTag)29   explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) {}
30 
~RefCountedBase()31   ~RefCountedBase() {}
32 
AddRef()33   void AddRef() const { AddRefImpl(); }
34 
35   // Returns true if the object should self-delete.
Release()36   bool Release() const {
37     --ref_count_;
38 
39     // TODO(maruel): Add back once it doesn't assert 500 times/sec.
40     // Current thread books the critical section "AddRelease"
41     // without release it.
42     // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
43 
44     return ref_count_ == 0;
45   }
46 
47   // Returns true if it is safe to read or write the object, from a thread
48   // safety standpoint. Should be DCHECK'd from the methods of RefCounted
49   // classes if there is a danger of objects being shared across threads.
50   //
51   // This produces fewer false positives than adding a separate SequenceChecker
52   // into the subclass, because it automatically detaches from the sequence when
53   // the reference count is 1 (and never fails if there is only one reference).
54   //
55   // This means unlike a separate SequenceChecker, it will permit a singly
56   // referenced object to be passed between threads (not holding a reference on
57   // the sending thread), but will trap if the sending thread holds onto a
58   // reference, or if the object is accessed from multiple threads
59   // simultaneously.
IsOnValidSequence()60   bool IsOnValidSequence() const { return true; }
61 
62  private:
63   template <typename U>
64   friend scoped_refptr<U> base::AdoptRef(U*);
65 
Adopted()66   void Adopted() const {}
67 
68 #if defined(ARCH_CPU_64_BIT)
69   void AddRefImpl() const;
70 #else
AddRefImpl()71   void AddRefImpl() const { ++ref_count_; }
72 #endif
73 
74   mutable uint32_t ref_count_ = 0;
75 
76   DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
77 };
78 
79 class RefCountedThreadSafeBase {
80  public:
81   bool HasOneRef() const;
82 
83  protected:
RefCountedThreadSafeBase(StartRefCountFromZeroTag)84   explicit constexpr RefCountedThreadSafeBase(StartRefCountFromZeroTag) {}
RefCountedThreadSafeBase(StartRefCountFromOneTag)85   explicit constexpr RefCountedThreadSafeBase(StartRefCountFromOneTag)
86       : ref_count_(1) {}
87 
88   ~RefCountedThreadSafeBase() = default;
89 
90 // Release and AddRef are suitable for inlining on X86 because they generate
91 // very small code sequences. On other platforms (ARM), it causes a size
92 // regression and is probably not worth it.
93 #if defined(ARCH_CPU_X86_FAMILY)
94   // Returns true if the object should self-delete.
Release()95   bool Release() const { return ReleaseImpl(); }
AddRef()96   void AddRef() const { AddRefImpl(); }
97 #else
98   // Returns true if the object should self-delete.
99   bool Release() const;
100   void AddRef() const;
101 #endif
102 
103  private:
104   template <typename U>
105   friend scoped_refptr<U> base::AdoptRef(U*);
106 
Adopted()107   void Adopted() const {}
108 
AddRefImpl()109   ALWAYS_INLINE void AddRefImpl() const { ref_count_.Increment(); }
110 
ReleaseImpl()111   ALWAYS_INLINE bool ReleaseImpl() const {
112     if (!ref_count_.Decrement()) {
113       return true;
114     }
115     return false;
116   }
117 
118   mutable AtomicRefCount ref_count_{0};
119 
120   DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase);
121 };
122 
123 }  // namespace subtle
124 
125 // ScopedAllowCrossThreadRefCountAccess disables the check documented on
126 // RefCounted below for rare pre-existing use cases where thread-safety was
127 // guaranteed through other means (e.g. explicit sequencing of calls across
128 // execution sequences when bouncing between threads in order). New callers
129 // should refrain from using this (callsites handling thread-safety through
130 // locks should use RefCountedThreadSafe per the overhead of its atomics being
131 // negligible compared to locks anyways and callsites doing explicit sequencing
132 // should properly std::move() the ref to avoid hitting this check).
133 // TODO(tzik): Cleanup existing use cases and remove
134 // ScopedAllowCrossThreadRefCountAccess.
135 class ScopedAllowCrossThreadRefCountAccess final {
136  public:
ScopedAllowCrossThreadRefCountAccess()137   ScopedAllowCrossThreadRefCountAccess() {}
~ScopedAllowCrossThreadRefCountAccess()138   ~ScopedAllowCrossThreadRefCountAccess() {}
139 };
140 
141 //
142 // A base class for reference counted classes.  Otherwise, known as a cheap
143 // knock-off of WebKit's RefCounted<T> class.  To use this, just extend your
144 // class from it like so:
145 //
146 //   class MyFoo : public base::RefCounted<MyFoo> {
147 //    ...
148 //    private:
149 //     friend class base::RefCounted<MyFoo>;
150 //     ~MyFoo();
151 //   };
152 //
153 // You should always make your destructor non-public, to avoid any code deleting
154 // the object accidently while there are references to it.
155 //
156 //
157 // The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs
158 // to trap unsafe cross thread usage. A subclass instance of RefCounted can be
159 // passed to another execution sequence only when its ref count is 1. If the ref
160 // count is more than 1, the RefCounted class verifies the ref updates are made
161 // on the same execution sequence as the previous ones. The subclass can also
162 // manually call IsOnValidSequence to trap other non-thread-safe accesses; see
163 // the documentation for that method.
164 //
165 //
166 // The reference count starts from zero by default, and we intended to migrate
167 // to start-from-one ref count. Put REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() to
168 // the ref counted class to opt-in.
169 //
170 // If an object has start-from-one ref count, the first scoped_refptr need to be
171 // created by base::AdoptRef() or base::MakeRefCounted(). We can use
172 // base::MakeRefCounted() to create create both type of ref counted object.
173 //
174 // The motivations to use start-from-one ref count are:
175 //  - Start-from-one ref count doesn't need the ref count increment for the
176 //    first reference.
177 //  - It can detect an invalid object acquisition for a being-deleted object
178 //    that has zero ref count. That tends to happen on custom deleter that
179 //    delays the deletion.
180 //    TODO(tzik): Implement invalid acquisition detection.
181 //  - Behavior parity to Blink's WTF::RefCounted, whose count starts from one.
182 //    And start-from-one ref count is a step to merge WTF::RefCounted into
183 //    base::RefCounted.
184 //
185 #define REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE()             \
186   static constexpr ::base::subtle::StartRefCountFromOneTag \
187       kRefCountPreference = ::base::subtle::kStartRefCountFromOneTag
188 
189 template <class T, typename Traits>
190 class RefCounted;
191 
192 template <typename T>
193 struct DefaultRefCountedTraits {
DestructDefaultRefCountedTraits194   static void Destruct(const T* x) {
195     RefCounted<T, DefaultRefCountedTraits>::DeleteInternal(x);
196   }
197 };
198 
199 template <class T, typename Traits = DefaultRefCountedTraits<T>>
200 class RefCounted : public subtle::RefCountedBase {
201  public:
202   static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference =
203       subtle::kStartRefCountFromZeroTag;
204 
RefCounted()205   RefCounted() : subtle::RefCountedBase(T::kRefCountPreference) {}
206 
AddRef()207   void AddRef() const { subtle::RefCountedBase::AddRef(); }
208 
Release()209   void Release() const {
210     if (subtle::RefCountedBase::Release()) {
211       // Prune the code paths which the static analyzer may take to simulate
212       // object destruction. Use-after-free errors aren't possible given the
213       // lifetime guarantees of the refcounting system.
214       ANALYZER_SKIP_THIS_PATH();
215 
216       Traits::Destruct(static_cast<const T*>(this));
217     }
218   }
219 
220  protected:
221   ~RefCounted() = default;
222 
223  private:
224   friend struct DefaultRefCountedTraits<T>;
225   template <typename U>
226   static void DeleteInternal(const U* x) {
227     delete x;
228   }
229 
230   DISALLOW_COPY_AND_ASSIGN(RefCounted);
231 };
232 
233 // Forward declaration.
234 template <class T, typename Traits>
235 class RefCountedThreadSafe;
236 
237 // Default traits for RefCountedThreadSafe<T>.  Deletes the object when its ref
238 // count reaches 0.  Overload to delete it on a different thread etc.
239 template <typename T>
240 struct DefaultRefCountedThreadSafeTraits {
241   static void Destruct(const T* x) {
242     // Delete through RefCountedThreadSafe to make child classes only need to be
243     // friend with RefCountedThreadSafe instead of this struct, which is an
244     // implementation detail.
245     RefCountedThreadSafe<T, DefaultRefCountedThreadSafeTraits>::DeleteInternal(
246         x);
247   }
248 };
249 
250 //
251 // A thread-safe variant of RefCounted<T>
252 //
253 //   class MyFoo : public base::RefCountedThreadSafe<MyFoo> {
254 //    ...
255 //   };
256 //
257 // If you're using the default trait, then you should add compile time
258 // asserts that no one else is deleting your object.  i.e.
259 //    private:
260 //     friend class base::RefCountedThreadSafe<MyFoo>;
261 //     ~MyFoo();
262 //
263 // We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe
264 // too. See the comment above the RefCounted definition for details.
265 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T>>
266 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
267  public:
268   static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference =
269       subtle::kStartRefCountFromZeroTag;
270 
271   explicit RefCountedThreadSafe()
272       : subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {}
273 
274   void AddRef() const { subtle::RefCountedThreadSafeBase::AddRef(); }
275 
276   void Release() const {
277     if (subtle::RefCountedThreadSafeBase::Release()) {
278       ANALYZER_SKIP_THIS_PATH();
279       Traits::Destruct(static_cast<const T*>(this));
280     }
281   }
282 
283  protected:
284   ~RefCountedThreadSafe() = default;
285 
286  private:
287   friend struct DefaultRefCountedThreadSafeTraits<T>;
288   template <typename U>
289   static void DeleteInternal(const U* x) {
290     delete x;
291   }
292 
293   DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe);
294 };
295 
296 //
297 // A thread-safe wrapper for some piece of data so we can place other
298 // things in scoped_refptrs<>.
299 //
300 template <typename T>
301 class RefCountedData
302     : public base::RefCountedThreadSafe<base::RefCountedData<T>> {
303  public:
304   RefCountedData() : data() {}
305   RefCountedData(const T& in_value) : data(in_value) {}
306   RefCountedData(T&& in_value) : data(std::move(in_value)) {}
307 
308   T data;
309 
310  private:
311   friend class base::RefCountedThreadSafe<base::RefCountedData<T>>;
312   ~RefCountedData() = default;
313 };
314 
315 }  // namespace base
316 
317 #endif  // BASE_MEMORY_REF_COUNTED_H_
318