1 // Copyright 2013 The Flutter 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 // Internal implementation details for ref_counted.h. 6 7 #ifndef FLUTTER_FML_MEMORY_REF_COUNTED_INTERNAL_H_ 8 #define FLUTTER_FML_MEMORY_REF_COUNTED_INTERNAL_H_ 9 10 #include <atomic> 11 12 #include "flutter/fml/logging.h" 13 #include "flutter/fml/macros.h" 14 15 namespace fml { 16 namespace internal { 17 18 // See ref_counted.h for comments on the public methods. 19 class RefCountedThreadSafeBase { 20 public: AddRef()21 void AddRef() const { 22 #ifndef NDEBUG 23 FML_DCHECK(!adoption_required_); 24 FML_DCHECK(!destruction_started_); 25 #endif 26 ref_count_.fetch_add(1u, std::memory_order_relaxed); 27 } 28 HasOneRef()29 bool HasOneRef() const { 30 return ref_count_.load(std::memory_order_acquire) == 1u; 31 } 32 AssertHasOneRef()33 void AssertHasOneRef() const { FML_DCHECK(HasOneRef()); } 34 35 protected: 36 RefCountedThreadSafeBase(); 37 ~RefCountedThreadSafeBase(); 38 39 // Returns true if the object should self-delete. Release()40 bool Release() const { 41 #ifndef NDEBUG 42 FML_DCHECK(!adoption_required_); 43 FML_DCHECK(!destruction_started_); 44 #endif 45 FML_DCHECK(ref_count_.load(std::memory_order_acquire) != 0u); 46 // TODO(vtl): We could add the following: 47 // if (ref_count_.load(std::memory_order_relaxed) == 1u) { 48 // #ifndef NDEBUG 49 // destruction_started_= true; 50 // #endif 51 // return true; 52 // } 53 // This would be correct. On ARM (an Nexus 4), in *single-threaded* tests, 54 // this seems to make the destruction case marginally faster (barely 55 // measurable), and while the non-destruction case remains about the same 56 // (possibly marginally slower, but my measurements aren't good enough to 57 // have any confidence in that). I should try multithreaded/multicore tests. 58 if (ref_count_.fetch_sub(1u, std::memory_order_release) == 1u) { 59 std::atomic_thread_fence(std::memory_order_acquire); 60 #ifndef NDEBUG 61 destruction_started_ = true; 62 #endif 63 return true; 64 } 65 return false; 66 } 67 68 #ifndef NDEBUG Adopt()69 void Adopt() { 70 FML_DCHECK(adoption_required_); 71 adoption_required_ = false; 72 } 73 #endif 74 75 private: 76 mutable std::atomic_uint_fast32_t ref_count_; 77 78 #ifndef NDEBUG 79 mutable bool adoption_required_; 80 mutable bool destruction_started_; 81 #endif 82 83 FML_DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); 84 }; 85 RefCountedThreadSafeBase()86inline RefCountedThreadSafeBase::RefCountedThreadSafeBase() 87 : ref_count_(1u) 88 #ifndef NDEBUG 89 , 90 adoption_required_(true), 91 destruction_started_(false) 92 #endif 93 { 94 } 95 ~RefCountedThreadSafeBase()96inline RefCountedThreadSafeBase::~RefCountedThreadSafeBase() { 97 #ifndef NDEBUG 98 FML_DCHECK(!adoption_required_); 99 // Should only be destroyed as a result of |Release()|. 100 FML_DCHECK(destruction_started_); 101 #endif 102 } 103 104 } // namespace internal 105 } // namespace fml 106 107 #endif // FLUTTER_FML_MEMORY_REF_COUNTED_INTERNAL_H_ 108