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