• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()86 inline RefCountedThreadSafeBase::RefCountedThreadSafeBase()
87     : ref_count_(1u)
88 #ifndef NDEBUG
89       ,
90       adoption_required_(true),
91       destruction_started_(false)
92 #endif
93 {
94 }
95 
~RefCountedThreadSafeBase()96 inline 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