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 | |
23 | namespace base { |
24 | namespace subtle { |
25 | |
26 | class 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 | |
150 | class 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. |
253 | class 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 | |
312 | template <class T, typename Traits> |
313 | class RefCounted; |
314 | |
315 | template <typename T> |
316 | struct DefaultRefCountedTraits { |
317 | static void Destruct(const T* x) { |
318 | RefCounted<T, DefaultRefCountedTraits>::DeleteInternal(x); |
319 | } |
320 | }; |
321 | |
322 | template <class T, typename Traits = DefaultRefCountedTraits<T>> |
323 | class 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. |
359 | template <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. |
363 | template<typename T> |
364 | struct 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. |
389 | template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > |
390 | class 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 | // |
432 | template<typename T> |
433 | class 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 | |