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