// Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Internal implementation details for ref_counted.h. #ifndef FLUTTER_FML_MEMORY_REF_COUNTED_INTERNAL_H_ #define FLUTTER_FML_MEMORY_REF_COUNTED_INTERNAL_H_ #include #include "flutter/fml/logging.h" #include "flutter/fml/macros.h" namespace fml { namespace internal { // See ref_counted.h for comments on the public methods. class RefCountedThreadSafeBase { public: void AddRef() const { #ifndef NDEBUG FML_DCHECK(!adoption_required_); FML_DCHECK(!destruction_started_); #endif ref_count_.fetch_add(1u, std::memory_order_relaxed); } bool HasOneRef() const { return ref_count_.load(std::memory_order_acquire) == 1u; } void AssertHasOneRef() const { FML_DCHECK(HasOneRef()); } protected: RefCountedThreadSafeBase(); ~RefCountedThreadSafeBase(); // Returns true if the object should self-delete. bool Release() const { #ifndef NDEBUG FML_DCHECK(!adoption_required_); FML_DCHECK(!destruction_started_); #endif FML_DCHECK(ref_count_.load(std::memory_order_acquire) != 0u); // TODO(vtl): We could add the following: // if (ref_count_.load(std::memory_order_relaxed) == 1u) { // #ifndef NDEBUG // destruction_started_= true; // #endif // return true; // } // This would be correct. On ARM (an Nexus 4), in *single-threaded* tests, // this seems to make the destruction case marginally faster (barely // measurable), and while the non-destruction case remains about the same // (possibly marginally slower, but my measurements aren't good enough to // have any confidence in that). I should try multithreaded/multicore tests. if (ref_count_.fetch_sub(1u, std::memory_order_release) == 1u) { std::atomic_thread_fence(std::memory_order_acquire); #ifndef NDEBUG destruction_started_ = true; #endif return true; } return false; } #ifndef NDEBUG void Adopt() { FML_DCHECK(adoption_required_); adoption_required_ = false; } #endif private: mutable std::atomic_uint_fast32_t ref_count_; #ifndef NDEBUG mutable bool adoption_required_; mutable bool destruction_started_; #endif FML_DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); }; inline RefCountedThreadSafeBase::RefCountedThreadSafeBase() : ref_count_(1u) #ifndef NDEBUG , adoption_required_(true), destruction_started_(false) #endif { } inline RefCountedThreadSafeBase::~RefCountedThreadSafeBase() { #ifndef NDEBUG FML_DCHECK(!adoption_required_); // Should only be destroyed as a result of |Release()|. FML_DCHECK(destruction_started_); #endif } } // namespace internal } // namespace fml #endif // FLUTTER_FML_MEMORY_REF_COUNTED_INTERNAL_H_