• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2012
2 // Google Inc. All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //    * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //    * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //    * Neither the name of Google Inc. nor the name Chromium Embedded
15 // Framework nor the names of its contributors may be used to endorse
16 // or promote products derived from this software without specific prior
17 // written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 //
31 
32 #ifndef CEF_INCLUDE_BASE_CEF_REF_COUNTED_H_
33 #define CEF_INCLUDE_BASE_CEF_REF_COUNTED_H_
34 #pragma once
35 
36 #if defined(USING_CHROMIUM_INCLUDES)
37 // When building CEF include the Chromium header directly.
38 #include "base/memory/ref_counted.h"
39 #else  // !USING_CHROMIUM_INCLUDES
40 // The following is substantially similar to the Chromium implementation.
41 // If the Chromium implementation diverges the below implementation should be
42 // updated to match.
43 
44 #include <stddef.h>
45 
46 #include <utility>
47 
48 #include "include/base/cef_atomic_ref_count.h"
49 #include "include/base/cef_build.h"
50 #include "include/base/cef_compiler_specific.h"
51 #include "include/base/cef_logging.h"
52 #include "include/base/cef_scoped_refptr.h"
53 #include "include/base/cef_template_util.h"
54 #include "include/base/cef_thread_checker.h"
55 
56 namespace base {
57 namespace cef_subtle {
58 
59 class RefCountedBase {
60  public:
HasOneRef()61   bool HasOneRef() const { return ref_count_ == 1; }
HasAtLeastOneRef()62   bool HasAtLeastOneRef() const { return ref_count_ >= 1; }
63 
64  protected:
RefCountedBase(StartRefCountFromZeroTag)65   explicit RefCountedBase(StartRefCountFromZeroTag) {
66 #if DCHECK_IS_ON()
67     thread_checker_.DetachFromThread();
68 #endif
69   }
70 
RefCountedBase(StartRefCountFromOneTag)71   explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) {
72 #if DCHECK_IS_ON()
73     needs_adopt_ref_ = true;
74     thread_checker_.DetachFromThread();
75 #endif
76   }
77 
78   RefCountedBase(const RefCountedBase&) = delete;
79   RefCountedBase& operator=(const RefCountedBase&) = delete;
80 
~RefCountedBase()81   ~RefCountedBase() {
82 #if DCHECK_IS_ON()
83     DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
84 #endif
85   }
86 
AddRef()87   void AddRef() const {
88 #if DCHECK_IS_ON()
89     DCHECK(!in_dtor_);
90     DCHECK(!needs_adopt_ref_)
91         << "This RefCounted object is created with non-zero reference count."
92         << " The first reference to such a object has to be made by AdoptRef or"
93         << " MakeRefCounted.";
94     if (ref_count_ >= 1) {
95       DCHECK(CalledOnValidThread());
96     }
97 #endif
98 
99     AddRefImpl();
100   }
101 
102   // Returns true if the object should self-delete.
Release()103   bool Release() const {
104     ReleaseImpl();
105 
106 #if DCHECK_IS_ON()
107     DCHECK(!in_dtor_);
108     if (ref_count_ == 0)
109       in_dtor_ = true;
110 
111     if (ref_count_ >= 1)
112       DCHECK(CalledOnValidThread());
113     if (ref_count_ == 1)
114       thread_checker_.DetachFromThread();
115 #endif
116 
117     return ref_count_ == 0;
118   }
119 
120   // Returns true if it is safe to read or write the object, from a thread
121   // safety standpoint. Should be DCHECK'd from the methods of RefCounted
122   // classes if there is a danger of objects being shared across threads.
123   //
124   // This produces fewer false positives than adding a separate ThreadChecker
125   // into the subclass, because it automatically detaches from the thread when
126   // the reference count is 1 (and never fails if there is only one reference).
127   //
128   // This means unlike a separate ThreadChecker, it will permit a singly
129   // referenced object to be passed between threads (not holding a reference on
130   // the sending thread), but will trap if the sending thread holds onto a
131   // reference, or if the object is accessed from multiple threads
132   // simultaneously.
IsOnValidThread()133   bool IsOnValidThread() const {
134 #if DCHECK_IS_ON()
135     return ref_count_ <= 1 || CalledOnValidThread();
136 #else
137     return true;
138 #endif
139   }
140 
141  private:
142   template <typename U>
143   friend scoped_refptr<U> base::AdoptRef(U*);
144 
Adopted()145   void Adopted() const {
146 #if DCHECK_IS_ON()
147     DCHECK(needs_adopt_ref_);
148     needs_adopt_ref_ = false;
149 #endif
150   }
151 
152 #if defined(ARCH_CPU_64_BITS)
153   void AddRefImpl() const;
154   void ReleaseImpl() const;
155 #else
AddRefImpl()156   void AddRefImpl() const { ++ref_count_; }
ReleaseImpl()157   void ReleaseImpl() const { --ref_count_; }
158 #endif
159 
160 #if DCHECK_IS_ON()
161   bool CalledOnValidThread() const;
162 #endif
163 
164   mutable uint32_t ref_count_ = 0;
165   static_assert(std::is_unsigned<decltype(ref_count_)>::value,
166                 "ref_count_ must be an unsigned type.");
167 
168 #if DCHECK_IS_ON()
169   mutable bool needs_adopt_ref_ = false;
170   mutable bool in_dtor_ = false;
171   mutable ThreadChecker thread_checker_;
172 #endif
173 };
174 
175 class RefCountedThreadSafeBase {
176  public:
177   bool HasOneRef() const;
178   bool HasAtLeastOneRef() const;
179 
180  protected:
RefCountedThreadSafeBase(StartRefCountFromZeroTag)181   explicit constexpr RefCountedThreadSafeBase(StartRefCountFromZeroTag) {}
RefCountedThreadSafeBase(StartRefCountFromOneTag)182   explicit constexpr RefCountedThreadSafeBase(StartRefCountFromOneTag)
183       : ref_count_(1) {
184 #if DCHECK_IS_ON()
185     needs_adopt_ref_ = true;
186 #endif
187   }
188 
189   RefCountedThreadSafeBase(const RefCountedThreadSafeBase&) = delete;
190   RefCountedThreadSafeBase& operator=(const RefCountedThreadSafeBase&) = delete;
191 
192 #if DCHECK_IS_ON()
193   ~RefCountedThreadSafeBase();
194 #else
195   ~RefCountedThreadSafeBase() = default;
196 #endif
197 
198 // Release and AddRef are suitable for inlining on X86 because they generate
199 // very small code threads. On other platforms (ARM), it causes a size
200 // regression and is probably not worth it.
201 #if defined(ARCH_CPU_X86_FAMILY)
202   // Returns true if the object should self-delete.
Release()203   bool Release() const { return ReleaseImpl(); }
AddRef()204   void AddRef() const { AddRefImpl(); }
AddRefWithCheck()205   void AddRefWithCheck() const { AddRefWithCheckImpl(); }
206 #else
207   // Returns true if the object should self-delete.
208   bool Release() const;
209   void AddRef() const;
210   void AddRefWithCheck() const;
211 #endif
212 
213  private:
214   template <typename U>
215   friend scoped_refptr<U> base::AdoptRef(U*);
216 
Adopted()217   void Adopted() const {
218 #if DCHECK_IS_ON()
219     DCHECK(needs_adopt_ref_);
220     needs_adopt_ref_ = false;
221 #endif
222   }
223 
AddRefImpl()224   ALWAYS_INLINE void AddRefImpl() const {
225 #if DCHECK_IS_ON()
226     DCHECK(!in_dtor_);
227     DCHECK(!needs_adopt_ref_)
228         << "This RefCounted object is created with non-zero reference count."
229         << " The first reference to such a object has to be made by AdoptRef or"
230         << " MakeRefCounted.";
231 #endif
232     ref_count_.Increment();
233   }
234 
AddRefWithCheckImpl()235   ALWAYS_INLINE void AddRefWithCheckImpl() const {
236 #if DCHECK_IS_ON()
237     DCHECK(!in_dtor_);
238     DCHECK(!needs_adopt_ref_)
239         << "This RefCounted object is created with non-zero reference count."
240         << " The first reference to such a object has to be made by AdoptRef or"
241         << " MakeRefCounted.";
242 #endif
243     CHECK(ref_count_.Increment() > 0);
244   }
245 
ReleaseImpl()246   ALWAYS_INLINE bool ReleaseImpl() const {
247 #if DCHECK_IS_ON()
248     DCHECK(!in_dtor_);
249     DCHECK(!ref_count_.IsZero());
250 #endif
251     if (!ref_count_.Decrement()) {
252 #if DCHECK_IS_ON()
253       in_dtor_ = true;
254 #endif
255       return true;
256     }
257     return false;
258   }
259 
260   mutable AtomicRefCount ref_count_{0};
261 #if DCHECK_IS_ON()
262   mutable bool needs_adopt_ref_ = false;
263   mutable bool in_dtor_ = false;
264 #endif
265 };
266 
267 // ScopedAllowCrossThreadRefCountAccess disables the check documented on
268 // RefCounted below for rare pre-existing use cases where thread-safety was
269 // guaranteed through other means (e.g. explicit sequencing of calls across
270 // execution threads when bouncing between threads in order). New callers
271 // should refrain from using this (callsites handling thread-safety through
272 // locks should use RefCountedThreadSafe per the overhead of its atomics being
273 // negligible compared to locks anyways and callsites doing explicit sequencing
274 // should properly std::move() the ref to avoid hitting this check).
275 // TODO(tzik): Cleanup existing use cases and remove
276 // ScopedAllowCrossThreadRefCountAccess.
277 class ScopedAllowCrossThreadRefCountAccess final {
278  public:
279 #if DCHECK_IS_ON()
280   ScopedAllowCrossThreadRefCountAccess();
281   ~ScopedAllowCrossThreadRefCountAccess();
282 #else
283   ScopedAllowCrossThreadRefCountAccess() {}
284   ~ScopedAllowCrossThreadRefCountAccess() {}
285 #endif
286 };
287 
288 }  // namespace cef_subtle
289 
290 using ScopedAllowCrossThreadRefCountAccess =
291     cef_subtle::ScopedAllowCrossThreadRefCountAccess;
292 
293 //
294 // A base class for reference counted classes.  Otherwise, known as a cheap
295 // knock-off of WebKit's RefCounted<T> class.  To use this, just extend your
296 // class from it like so:
297 //
298 //   class MyFoo : public base::RefCounted<MyFoo> {
299 //    ...
300 //    private:
301 //     friend class base::RefCounted<MyFoo>;
302 //     ~MyFoo();
303 //   };
304 //
305 // Usage Notes:
306 // 1. You should always make your destructor non-public, to avoid any code
307 // deleting the object accidentally while there are references to it.
308 // 2. You should always make the ref-counted base class a friend of your class,
309 // so that it can access the destructor.
310 //
311 // The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs
312 // to trap unsafe cross thread usage. A subclass instance of RefCounted can be
313 // passed to another execution thread only when its ref count is 1. If the ref
314 // count is more than 1, the RefCounted class verifies the ref updates are made
315 // on the same execution thread as the previous ones. The subclass can also
316 // manually call IsOnValidThread to trap other non-thread-safe accesses; see
317 // the documentation for that method.
318 //
319 //
320 // The reference count starts from zero by default, and we intended to migrate
321 // to start-from-one ref count. Put REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() to
322 // the ref counted class to opt-in.
323 //
324 // If an object has start-from-one ref count, the first scoped_refptr need to be
325 // created by base::AdoptRef() or base::MakeRefCounted(). We can use
326 // base::MakeRefCounted() to create create both type of ref counted object.
327 //
328 // The motivations to use start-from-one ref count are:
329 //  - Start-from-one ref count doesn't need the ref count increment for the
330 //    first reference.
331 //  - It can detect an invalid object acquisition for a being-deleted object
332 //    that has zero ref count. That tends to happen on custom deleter that
333 //    delays the deletion.
334 //    TODO(tzik): Implement invalid acquisition detection.
335 //  - Behavior parity to Blink's WTF::RefCounted, whose count starts from one.
336 //    And start-from-one ref count is a step to merge WTF::RefCounted into
337 //    base::RefCounted.
338 //
339 #define REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE()                 \
340   static constexpr ::base::cef_subtle::StartRefCountFromOneTag \
341       kRefCountPreference = ::base::cef_subtle::kStartRefCountFromOneTag
342 
343 template <class T, typename Traits>
344 class RefCounted;
345 
346 template <typename T>
347 struct DefaultRefCountedTraits {
DestructDefaultRefCountedTraits348   static void Destruct(const T* x) {
349     RefCounted<T, DefaultRefCountedTraits>::DeleteInternal(x);
350   }
351 };
352 
353 template <class T, typename Traits = DefaultRefCountedTraits<T>>
354 class RefCounted : public cef_subtle::RefCountedBase {
355  public:
356   static constexpr cef_subtle::StartRefCountFromZeroTag kRefCountPreference =
357       cef_subtle::kStartRefCountFromZeroTag;
358 
RefCounted()359   RefCounted() : cef_subtle::RefCountedBase(T::kRefCountPreference) {}
360 
361   RefCounted(const RefCounted&) = delete;
362   RefCounted& operator=(const RefCounted&) = delete;
363 
AddRef()364   void AddRef() const { cef_subtle::RefCountedBase::AddRef(); }
365 
Release()366   void Release() const {
367     if (cef_subtle::RefCountedBase::Release()) {
368       // Prune the code paths which the static analyzer may take to simulate
369       // object destruction. Use-after-free errors aren't possible given the
370       // lifetime guarantees of the refcounting system.
371       ANALYZER_SKIP_THIS_PATH();
372 
373       Traits::Destruct(static_cast<const T*>(this));
374     }
375   }
376 
377  protected:
378   ~RefCounted() = default;
379 
380  private:
381   friend struct DefaultRefCountedTraits<T>;
382   template <typename U>
383   static void DeleteInternal(const U* x) {
384     delete x;
385   }
386 };
387 
388 // Forward declaration.
389 template <class T, typename Traits>
390 class RefCountedThreadSafe;
391 
392 // Default traits for RefCountedThreadSafe<T>.  Deletes the object when its ref
393 // count reaches 0.  Overload to delete it on a different thread etc.
394 template <typename T>
395 struct DefaultRefCountedThreadSafeTraits {
396   static void Destruct(const T* x) {
397     // Delete through RefCountedThreadSafe to make child classes only need to be
398     // friend with RefCountedThreadSafe instead of this struct, which is an
399     // implementation detail.
400     RefCountedThreadSafe<T, DefaultRefCountedThreadSafeTraits>::DeleteInternal(
401         x);
402   }
403 };
404 
405 //
406 // A thread-safe variant of RefCounted<T>
407 //
408 //   class MyFoo : public base::RefCountedThreadSafe<MyFoo> {
409 //    ...
410 //   };
411 //
412 // If you're using the default trait, then you should add compile time
413 // asserts that no one else is deleting your object.  i.e.
414 //    private:
415 //     friend class base::RefCountedThreadSafe<MyFoo>;
416 //     ~MyFoo();
417 //
418 // We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe
419 // too. See the comment above the RefCounted definition for details.
420 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T>>
421 class RefCountedThreadSafe : public cef_subtle::RefCountedThreadSafeBase {
422  public:
423   static constexpr cef_subtle::StartRefCountFromZeroTag kRefCountPreference =
424       cef_subtle::kStartRefCountFromZeroTag;
425 
426   explicit RefCountedThreadSafe()
427       : cef_subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {}
428 
429   RefCountedThreadSafe(const RefCountedThreadSafe&) = delete;
430   RefCountedThreadSafe& operator=(const RefCountedThreadSafe&) = delete;
431 
432   void AddRef() const { AddRefImpl(T::kRefCountPreference); }
433 
434   void Release() const {
435     if (cef_subtle::RefCountedThreadSafeBase::Release()) {
436       ANALYZER_SKIP_THIS_PATH();
437       Traits::Destruct(static_cast<const T*>(this));
438     }
439   }
440 
441  protected:
442   ~RefCountedThreadSafe() = default;
443 
444  private:
445   friend struct DefaultRefCountedThreadSafeTraits<T>;
446   template <typename U>
447   static void DeleteInternal(const U* x) {
448     delete x;
449   }
450 
451   void AddRefImpl(cef_subtle::StartRefCountFromZeroTag) const {
452     cef_subtle::RefCountedThreadSafeBase::AddRef();
453   }
454 
455   void AddRefImpl(cef_subtle::StartRefCountFromOneTag) const {
456     cef_subtle::RefCountedThreadSafeBase::AddRefWithCheck();
457   }
458 };
459 
460 //
461 // A thread-safe wrapper for some piece of data so we can place other
462 // things in scoped_refptrs<>.
463 //
464 template <typename T>
465 class RefCountedData
466     : public base::RefCountedThreadSafe<base::RefCountedData<T>> {
467  public:
468   RefCountedData() : data() {}
469   RefCountedData(const T& in_value) : data(in_value) {}
470   RefCountedData(T&& in_value) : data(std::move(in_value)) {}
471   template <typename... Args>
472   explicit RefCountedData(in_place_t, Args&&... args)
473       : data(std::forward<Args>(args)...) {}
474 
475   T data;
476 
477  private:
478   friend class base::RefCountedThreadSafe<base::RefCountedData<T>>;
479   ~RefCountedData() = default;
480 };
481 
482 template <typename T>
483 bool operator==(const RefCountedData<T>& lhs, const RefCountedData<T>& rhs) {
484   return lhs.data == rhs.data;
485 }
486 
487 template <typename T>
488 bool operator!=(const RefCountedData<T>& lhs, const RefCountedData<T>& rhs) {
489   return !(lhs == rhs);
490 }
491 
492 }  // namespace base
493 
494 #endif  // !USING_CHROMIUM_INCLUDES
495 
496 #endif  // CEF_INCLUDE_BASE_CEF_REF_COUNTED_H_
497