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