xref: /aosp_15_r20/external/cronet/base/memory/ref_counted.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 BASE_MEMORY_REF_COUNTED_H_
6 #define BASE_MEMORY_REF_COUNTED_H_
7 
8 #include <stddef.h>
9 
10 #include <limits>
11 #include <utility>
12 
13 #include "base/atomic_ref_count.h"
14 #include "base/base_export.h"
15 #include "base/check.h"
16 #include "base/check_op.h"
17 #include "base/compiler_specific.h"
18 #include "base/dcheck_is_on.h"
19 #include "base/memory/scoped_refptr.h"
20 #include "base/sequence_checker.h"
21 #include "base/template_util.h"
22 #include "base/threading/thread_collision_warner.h"
23 #include "build/build_config.h"
24 #include "third_party/abseil-cpp/absl/utility/utility.h"
25 
26 namespace base {
27 namespace subtle {
28 
29 class BASE_EXPORT RefCountedBase {
30  public:
31   RefCountedBase(const RefCountedBase&) = delete;
32   RefCountedBase& operator=(const RefCountedBase&) = delete;
33 
HasOneRef()34   bool HasOneRef() const { return ref_count_ == 1; }
HasAtLeastOneRef()35   bool HasAtLeastOneRef() const { return ref_count_ >= 1; }
36 
37  protected:
RefCountedBase(StartRefCountFromZeroTag)38   explicit RefCountedBase(StartRefCountFromZeroTag) {
39 #if DCHECK_IS_ON()
40     sequence_checker_.DetachFromSequence();
41 #endif
42   }
43 
RefCountedBase(StartRefCountFromOneTag)44   explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) {
45 #if DCHECK_IS_ON()
46     needs_adopt_ref_ = true;
47     sequence_checker_.DetachFromSequence();
48 #endif
49   }
50 
~RefCountedBase()51   ~RefCountedBase() {
52 #if DCHECK_IS_ON()
53     // RefCounted object deleted without calling Release()
54     DCHECK(in_dtor_);
55 #endif
56   }
57 
AddRef()58   void AddRef() const {
59 #if DCHECK_IS_ON()
60     DCHECK(!in_dtor_);
61     // This RefCounted object is created with non-zero reference count.
62     // The first reference to such a object has to be made by AdoptRef or
63     // MakeRefCounted.
64     DCHECK(!needs_adopt_ref_);
65     if (ref_count_ >= 1) {
66       DCHECK(CalledOnValidSequence());
67     }
68 #endif
69 
70     AddRefImpl();
71   }
72 
73   // Returns true if the object should self-delete.
Release()74   bool Release() const {
75     ReleaseImpl();
76 
77 #if DCHECK_IS_ON()
78     DCHECK(!in_dtor_);
79     if (ref_count_ == 0)
80       in_dtor_ = true;
81 
82     if (ref_count_ >= 1)
83       DCHECK(CalledOnValidSequence());
84     if (ref_count_ == 1)
85       sequence_checker_.DetachFromSequence();
86 #endif
87 
88     return ref_count_ == 0;
89   }
90 
91   // Returns true if it is safe to read or write the object, from a thread
92   // safety standpoint. Should be DCHECK'd from the methods of RefCounted
93   // classes if there is a danger of objects being shared across threads.
94   //
95   // This produces fewer false positives than adding a separate SequenceChecker
96   // into the subclass, because it automatically detaches from the sequence when
97   // the reference count is 1 (and never fails if there is only one reference).
98   //
99   // This means unlike a separate SequenceChecker, it will permit a singly
100   // referenced object to be passed between threads (not holding a reference on
101   // the sending thread), but will trap if the sending thread holds onto a
102   // reference, or if the object is accessed from multiple threads
103   // simultaneously.
IsOnValidSequence()104   bool IsOnValidSequence() const {
105 #if DCHECK_IS_ON()
106     return ref_count_ <= 1 || CalledOnValidSequence();
107 #else
108     return true;
109 #endif
110   }
111 
112  private:
113   template <typename U>
114   friend scoped_refptr<U> base::AdoptRef(U*);
115 
116   friend class RefCountedOverflowTest;
117 
Adopted()118   void Adopted() const {
119 #if DCHECK_IS_ON()
120     DCHECK(needs_adopt_ref_);
121     needs_adopt_ref_ = false;
122 #endif
123   }
124 
125 #if defined(ARCH_CPU_64_BITS)
126   void AddRefImpl() const;
127   void ReleaseImpl() const;
128 #else
AddRefImpl()129   void AddRefImpl() const { ++ref_count_; }
ReleaseImpl()130   void ReleaseImpl() const { --ref_count_; }
131 #endif
132 
133 #if DCHECK_IS_ON()
134   bool CalledOnValidSequence() const;
135 #endif
136 
137   mutable uint32_t ref_count_ = 0;
138   static_assert(std::is_unsigned_v<decltype(ref_count_)>,
139                 "ref_count_ must be an unsigned type.");
140 
141 #if DCHECK_IS_ON()
142   mutable bool needs_adopt_ref_ = false;
143   mutable bool in_dtor_ = false;
144   mutable SequenceChecker sequence_checker_;
145 #endif
146 
147   DFAKE_MUTEX(add_release_);
148 };
149 
150 class BASE_EXPORT RefCountedThreadSafeBase {
151  public:
152   RefCountedThreadSafeBase(const RefCountedThreadSafeBase&) = delete;
153   RefCountedThreadSafeBase& operator=(const RefCountedThreadSafeBase&) = delete;
154 
155   bool HasOneRef() const;
156   bool HasAtLeastOneRef() const;
157 
158  protected:
RefCountedThreadSafeBase(StartRefCountFromZeroTag)159   explicit constexpr RefCountedThreadSafeBase(StartRefCountFromZeroTag) {}
RefCountedThreadSafeBase(StartRefCountFromOneTag)160   explicit constexpr RefCountedThreadSafeBase(StartRefCountFromOneTag)
161       : ref_count_(1) {
162 #if DCHECK_IS_ON()
163     needs_adopt_ref_ = true;
164 #endif
165   }
166 
167 #if DCHECK_IS_ON()
168   ~RefCountedThreadSafeBase();
169 #else
170   ~RefCountedThreadSafeBase() = default;
171 #endif
172 
173 // Release and AddRef are suitable for inlining on X86 because they generate
174 // very small code sequences.
175 //
176 // ARM64 devices supporting ARMv8.1-A atomic instructions generate very little
177 // code, e.g. fetch_add() with acquire ordering is a single instruction (ldadd),
178 // vs LL/SC in previous ARM architectures. Inline it there as well.
179 //
180 // On other platforms (e.g. ARM), it causes a size regression and is probably
181 // not worth it.
182 #if defined(ARCH_CPU_X86_FAMILY) || defined(__ARM_FEATURE_ATOMICS)
183   // Returns true if the object should self-delete.
Release()184   bool Release() const { return ReleaseImpl(); }
AddRef()185   void AddRef() const { AddRefImpl(); }
AddRefWithCheck()186   void AddRefWithCheck() const { AddRefWithCheckImpl(); }
187 #else
188   // Returns true if the object should self-delete.
189   bool Release() const;
190   void AddRef() const;
191   void AddRefWithCheck() const;
192 #endif
193 
194  private:
195   template <typename U>
196   friend scoped_refptr<U> base::AdoptRef(U*);
197 
198   friend class RefCountedOverflowTest;
199 
Adopted()200   void Adopted() const {
201 #if DCHECK_IS_ON()
202     DCHECK(needs_adopt_ref_);
203     needs_adopt_ref_ = false;
204 #endif
205   }
206 
AddRefImpl()207   ALWAYS_INLINE void AddRefImpl() const {
208 #if DCHECK_IS_ON()
209     DCHECK(!in_dtor_);
210     // This RefCounted object is created with non-zero reference count.
211     // The first reference to such a object has to be made by AdoptRef or
212     // MakeRefCounted.
213     DCHECK(!needs_adopt_ref_);
214 #endif
215     CHECK_NE(ref_count_.Increment(), std::numeric_limits<int>::max());
216   }
217 
AddRefWithCheckImpl()218   ALWAYS_INLINE void AddRefWithCheckImpl() const {
219 #if DCHECK_IS_ON()
220     DCHECK(!in_dtor_);
221     // This RefCounted object is created with non-zero reference count.
222     // The first reference to such a object has to be made by AdoptRef or
223     // MakeRefCounted.
224     DCHECK(!needs_adopt_ref_);
225 #endif
226     int pre_increment_count = ref_count_.Increment();
227     CHECK_GT(pre_increment_count, 0);
228     CHECK_NE(pre_increment_count, std::numeric_limits<int>::max());
229   }
230 
ReleaseImpl()231   ALWAYS_INLINE bool ReleaseImpl() const {
232 #if DCHECK_IS_ON()
233     DCHECK(!in_dtor_);
234     DCHECK(!ref_count_.IsZero());
235 #endif
236     if (!ref_count_.Decrement()) {
237 #if DCHECK_IS_ON()
238       in_dtor_ = true;
239 #endif
240       return true;
241     }
242     return false;
243   }
244 
245   mutable AtomicRefCount ref_count_{0};
246 #if DCHECK_IS_ON()
247   mutable bool needs_adopt_ref_ = false;
248   mutable bool in_dtor_ = false;
249 #endif
250 };
251 
252 }  // namespace subtle
253 
254 // ScopedAllowCrossThreadRefCountAccess disables the check documented on
255 // RefCounted below for rare pre-existing use cases where thread-safety was
256 // guaranteed through other means (e.g. explicit sequencing of calls across
257 // execution sequences when bouncing between threads in order). New callers
258 // should refrain from using this (callsites handling thread-safety through
259 // locks should use RefCountedThreadSafe per the overhead of its atomics being
260 // negligible compared to locks anyways and callsites doing explicit sequencing
261 // should properly std::move() the ref to avoid hitting this check).
262 // TODO(tzik): Cleanup existing use cases and remove
263 // ScopedAllowCrossThreadRefCountAccess.
264 class BASE_EXPORT ScopedAllowCrossThreadRefCountAccess final {
265  public:
266 #if DCHECK_IS_ON()
267   ScopedAllowCrossThreadRefCountAccess();
268   ~ScopedAllowCrossThreadRefCountAccess();
269 #else
270   ScopedAllowCrossThreadRefCountAccess() {}
271   ~ScopedAllowCrossThreadRefCountAccess() {}
272 #endif
273 };
274 
275 //
276 // A base class for reference counted classes.  Otherwise, known as a cheap
277 // knock-off of WebKit's RefCounted<T> class.  To use this, just extend your
278 // class from it like so:
279 //
280 //   class MyFoo : public base::RefCounted<MyFoo> {
281 //    ...
282 //    private:
283 //     friend class base::RefCounted<MyFoo>;
284 //     ~MyFoo();
285 //   };
286 //
287 // Usage Notes:
288 // 1. You should always make your destructor non-public, to avoid any code
289 // deleting the object accidentally while there are references to it.
290 // 2. You should always make the ref-counted base class a friend of your class,
291 // so that it can access the destructor.
292 //
293 // The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs
294 // to trap unsafe cross thread usage. A subclass instance of RefCounted can be
295 // passed to another execution sequence only when its ref count is 1. If the ref
296 // count is more than 1, the RefCounted class verifies the ref updates are made
297 // on the same execution sequence as the previous ones. The subclass can also
298 // manually call IsOnValidSequence to trap other non-thread-safe accesses; see
299 // the documentation for that method.
300 //
301 //
302 // The reference count starts from zero by default, and we intended to migrate
303 // to start-from-one ref count. Put REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() to
304 // the ref counted class to opt-in.
305 //
306 // If an object has start-from-one ref count, the first scoped_refptr need to be
307 // created by base::AdoptRef() or base::MakeRefCounted(). We can use
308 // base::MakeRefCounted() to create create both type of ref counted object.
309 //
310 // The motivations to use start-from-one ref count are:
311 //  - Start-from-one ref count doesn't need the ref count increment for the
312 //    first reference.
313 //  - It can detect an invalid object acquisition for a being-deleted object
314 //    that has zero ref count. That tends to happen on custom deleter that
315 //    delays the deletion.
316 //    TODO(tzik): Implement invalid acquisition detection.
317 //  - Behavior parity to Blink's WTF::RefCounted, whose count starts from one.
318 //    And start-from-one ref count is a step to merge WTF::RefCounted into
319 //    base::RefCounted.
320 //
321 #define REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() \
322   using RefCountPreferenceTag = ::base::subtle::StartRefCountFromOneTag
323 
324 template <class T, typename Traits>
325 class RefCounted;
326 
327 template <typename T>
328 struct DefaultRefCountedTraits {
DestructDefaultRefCountedTraits329   static void Destruct(const T* x) {
330     RefCounted<T, DefaultRefCountedTraits>::DeleteInternal(x);
331   }
332 };
333 
334 template <class T, typename Traits = DefaultRefCountedTraits<T>>
335 class RefCounted : public subtle::RefCountedBase {
336  public:
337   using RefCountPreferenceTag = subtle::StartRefCountFromZeroTag;
338 
RefCounted()339   RefCounted() : subtle::RefCountedBase(subtle::GetRefCountPreference<T>()) {}
340 
341   RefCounted(const RefCounted&) = delete;
342   RefCounted& operator=(const RefCounted&) = delete;
343 
AddRef()344   void AddRef() const {
345     subtle::RefCountedBase::AddRef();
346   }
347 
Release()348   void Release() const {
349     if (subtle::RefCountedBase::Release()) {
350       // Prune the code paths which the static analyzer may take to simulate
351       // object destruction. Use-after-free errors aren't possible given the
352       // lifetime guarantees of the refcounting system.
353       ANALYZER_SKIP_THIS_PATH();
354 
355       Traits::Destruct(static_cast<const T*>(this));
356     }
357   }
358 
359  protected:
360   ~RefCounted() = default;
361 
362  private:
363   friend struct DefaultRefCountedTraits<T>;
364   template <typename U>
365   static void DeleteInternal(const U* x) {
366     delete x;
367   }
368 };
369 
370 // Forward declaration.
371 template <class T, typename Traits> class RefCountedThreadSafe;
372 
373 // Default traits for RefCountedThreadSafe<T>.  Deletes the object when its ref
374 // count reaches 0.  Overload to delete it on a different thread etc.
375 template<typename T>
376 struct DefaultRefCountedThreadSafeTraits {
377   static void Destruct(const T* x) {
378     // Delete through RefCountedThreadSafe to make child classes only need to be
379     // friend with RefCountedThreadSafe instead of this struct, which is an
380     // implementation detail.
381     RefCountedThreadSafe<T,
382                          DefaultRefCountedThreadSafeTraits>::DeleteInternal(x);
383   }
384 };
385 
386 //
387 // A thread-safe variant of RefCounted<T>
388 //
389 //   class MyFoo : public base::RefCountedThreadSafe<MyFoo> {
390 //    ...
391 //   };
392 //
393 // If you're using the default trait, then you should add compile time
394 // asserts that no one else is deleting your object.  i.e.
395 //    private:
396 //     friend class base::RefCountedThreadSafe<MyFoo>;
397 //     ~MyFoo();
398 //
399 // We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe
400 // too. See the comment above the RefCounted definition for details.
401 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> >
402 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
403  public:
404   using RefCountPreferenceTag = subtle::StartRefCountFromZeroTag;
405 
406   explicit RefCountedThreadSafe()
407       : subtle::RefCountedThreadSafeBase(subtle::GetRefCountPreference<T>()) {}
408 
409   RefCountedThreadSafe(const RefCountedThreadSafe&) = delete;
410   RefCountedThreadSafe& operator=(const RefCountedThreadSafe&) = delete;
411 
412   void AddRef() const { AddRefImpl(subtle::GetRefCountPreference<T>()); }
413 
414   void Release() const {
415     if (subtle::RefCountedThreadSafeBase::Release()) {
416       ANALYZER_SKIP_THIS_PATH();
417       Traits::Destruct(static_cast<const T*>(this));
418     }
419   }
420 
421  protected:
422   ~RefCountedThreadSafe() = default;
423 
424  private:
425   friend struct DefaultRefCountedThreadSafeTraits<T>;
426   template <typename U>
427   static void DeleteInternal(const U* x) {
428     delete x;
429   }
430 
431   void AddRefImpl(subtle::StartRefCountFromZeroTag) const {
432     subtle::RefCountedThreadSafeBase::AddRef();
433   }
434 
435   void AddRefImpl(subtle::StartRefCountFromOneTag) const {
436     subtle::RefCountedThreadSafeBase::AddRefWithCheck();
437   }
438 };
439 
440 //
441 // A thread-safe wrapper for some piece of data so we can place other
442 // things in scoped_refptrs<>.
443 //
444 template<typename T>
445 class RefCountedData
446     : public base::RefCountedThreadSafe< base::RefCountedData<T> > {
447  public:
448   RefCountedData() : data() {}
449   RefCountedData(const T& in_value) : data(in_value) {}
450   RefCountedData(T&& in_value) : data(std::move(in_value)) {}
451   template <typename... Args>
452   explicit RefCountedData(std::in_place_t, Args&&... args)
453       : data(std::forward<Args>(args)...) {}
454 
455   T data;
456 
457  private:
458   friend class base::RefCountedThreadSafe<base::RefCountedData<T> >;
459   ~RefCountedData() = default;
460 };
461 
462 template <typename T>
463 bool operator==(const RefCountedData<T>& lhs, const RefCountedData<T>& rhs) {
464   return lhs.data == rhs.data;
465 }
466 
467 template <typename T>
468 bool operator!=(const RefCountedData<T>& lhs, const RefCountedData<T>& rhs) {
469   return !(lhs == rhs);
470 }
471 
472 }  // namespace base
473 
474 #endif  // BASE_MEMORY_REF_COUNTED_H_
475