Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc / deps / grpc / src / core / lib / gprpp / ref_counted.h
1 /*
2  *
3  * Copyright 2017 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18
19 #ifndef GRPC_CORE_LIB_GPRPP_REF_COUNTED_H
20 #define GRPC_CORE_LIB_GPRPP_REF_COUNTED_H
21
22 #include <grpc/support/port_platform.h>
23
24 #include <grpc/support/atm.h>
25 #include <grpc/support/log.h>
26 #include <grpc/support/sync.h>
27
28 #include <atomic>
29 #include <cassert>
30 #include <cinttypes>
31
32 #include "src/core/lib/debug/trace.h"
33 #include "src/core/lib/gprpp/abstract.h"
34 #include "src/core/lib/gprpp/atomic.h"
35 #include "src/core/lib/gprpp/debug_location.h"
36 #include "src/core/lib/gprpp/memory.h"
37 #include "src/core/lib/gprpp/ref_counted_ptr.h"
38
39 namespace grpc_core {
40
41 // PolymorphicRefCount enforces polymorphic destruction of RefCounted.
42 class PolymorphicRefCount {
43  public:
44   GRPC_ABSTRACT_BASE_CLASS
45
46  protected:
47   GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
48
49   virtual ~PolymorphicRefCount() = default;
50 };
51
52 // NonPolymorphicRefCount does not enforce polymorphic destruction of
53 // RefCounted. Please refer to grpc_core::RefCounted for more details, and
54 // when in doubt use PolymorphicRefCount.
55 class NonPolymorphicRefCount {
56  public:
57   GRPC_ABSTRACT_BASE_CLASS
58
59  protected:
60   GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
61
62   ~NonPolymorphicRefCount() = default;
63 };
64
65 // RefCount is a simple atomic ref-count.
66 //
67 // This is a C++ implementation of gpr_refcount, with inline functions. Due to
68 // inline functions, this class is significantly more efficient than
69 // gpr_refcount and should be preferred over gpr_refcount whenever possible.
70 //
71 // TODO(soheil): Remove gpr_refcount after submitting the GRFC and the paragraph
72 //               above.
73 class RefCount {
74  public:
75   using Value = intptr_t;
76
77   // `init` is the initial refcount stored in this object.
78   //
79   // TraceFlagT is defined to accept both DebugOnlyTraceFlag and TraceFlag.
80   // Note: RefCount tracing is only enabled on debug builds, even when a
81   //       TraceFlag is used.
82   template <typename TraceFlagT = TraceFlag>
83   constexpr explicit RefCount(Value init = 1, TraceFlagT* trace_flag = nullptr)
84       :
85 #ifndef NDEBUG
86         trace_flag_(trace_flag),
87 #endif
88         value_(init) {
89   }
90
91   // Increases the ref-count by `n`.
92   void Ref(Value n = 1) {
93 #ifndef NDEBUG
94     const Value prior = value_.FetchAdd(n, MemoryOrder::RELAXED);
95     if (trace_flag_ != nullptr && trace_flag_->enabled()) {
96       gpr_log(GPR_INFO, "%s:%p ref %" PRIdPTR " -> %" PRIdPTR,
97               trace_flag_->name(), this, prior, prior + n);
98     }
99 #else
100     value_.FetchAdd(n, MemoryOrder::RELAXED);
101 #endif
102   }
103   void Ref(const DebugLocation& location, const char* reason, Value n = 1) {
104 #ifndef NDEBUG
105     const Value prior = value_.FetchAdd(n, MemoryOrder::RELAXED);
106     if (trace_flag_ != nullptr && trace_flag_->enabled()) {
107       gpr_log(GPR_INFO, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s",
108               trace_flag_->name(), this, location.file(), location.line(),
109               prior, prior + n, reason);
110     }
111 #else
112     value_.FetchAdd(n, MemoryOrder::RELAXED);
113 #endif
114   }
115
116   // Similar to Ref() with an assert on the ref-count being non-zero.
117   void RefNonZero() {
118 #ifndef NDEBUG
119     const Value prior = value_.FetchAdd(1, MemoryOrder::RELAXED);
120     if (trace_flag_ != nullptr && trace_flag_->enabled()) {
121       gpr_log(GPR_INFO, "%s:%p ref %" PRIdPTR " -> %" PRIdPTR,
122               trace_flag_->name(), this, prior, prior + 1);
123     }
124     assert(prior > 0);
125 #else
126     value_.FetchAdd(1, MemoryOrder::RELAXED);
127 #endif
128   }
129   void RefNonZero(const DebugLocation& location, const char* reason) {
130 #ifndef NDEBUG
131     const Value prior = value_.FetchAdd(1, MemoryOrder::RELAXED);
132     if (trace_flag_ != nullptr && trace_flag_->enabled()) {
133       gpr_log(GPR_INFO, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s",
134               trace_flag_->name(), this, location.file(), location.line(),
135               prior, prior + 1, reason);
136     }
137     assert(prior > 0);
138 #else
139     RefNonZero();
140 #endif
141   }
142
143   bool RefIfNonZero() {
144 #ifndef NDEBUG
145     if (trace_flag_ != nullptr && trace_flag_->enabled()) {
146       const Value prior = get();
147       gpr_log(GPR_INFO, "%s:%p ref_if_non_zero %" PRIdPTR " -> %" PRIdPTR,
148               trace_flag_->name(), this, prior, prior + 1);
149     }
150 #endif
151     return value_.IncrementIfNonzero();
152   }
153   bool RefIfNonZero(const DebugLocation& location, const char* reason) {
154 #ifndef NDEBUG
155     if (trace_flag_ != nullptr && trace_flag_->enabled()) {
156       const Value prior = get();
157       gpr_log(GPR_INFO,
158               "%s:%p %s:%d ref_if_non_zero "
159               "%" PRIdPTR " -> %" PRIdPTR " %s",
160               trace_flag_->name(), this, location.file(), location.line(),
161               prior, prior + 1, reason);
162     }
163 #endif
164     return value_.IncrementIfNonzero();
165   }
166
167   // Decrements the ref-count and returns true if the ref-count reaches 0.
168   bool Unref() {
169 #ifndef NDEBUG
170     // Grab a copy of the trace flag before the atomic change, since we
171     // can't safely access it afterwards if we're going to be freed.
172     auto* trace_flag = trace_flag_;
173 #endif
174     const Value prior = value_.FetchSub(1, MemoryOrder::ACQ_REL);
175 #ifndef NDEBUG
176     if (trace_flag != nullptr && trace_flag->enabled()) {
177       gpr_log(GPR_INFO, "%s:%p unref %" PRIdPTR " -> %" PRIdPTR,
178               trace_flag->name(), this, prior, prior - 1);
179     }
180     GPR_DEBUG_ASSERT(prior > 0);
181 #endif
182     return prior == 1;
183   }
184   bool Unref(const DebugLocation& location, const char* reason) {
185 #ifndef NDEBUG
186     // Grab a copy of the trace flag before the atomic change, since we
187     // can't safely access it afterwards if we're going to be freed.
188     auto* trace_flag = trace_flag_;
189 #endif
190     const Value prior = value_.FetchSub(1, MemoryOrder::ACQ_REL);
191 #ifndef NDEBUG
192     if (trace_flag != nullptr && trace_flag->enabled()) {
193       gpr_log(GPR_INFO, "%s:%p %s:%d unref %" PRIdPTR " -> %" PRIdPTR " %s",
194               trace_flag->name(), this, location.file(), location.line(), prior,
195               prior - 1, reason);
196     }
197     GPR_DEBUG_ASSERT(prior > 0);
198 #endif
199     return prior == 1;
200   }
201
202  private:
203   Value get() const { return value_.Load(MemoryOrder::RELAXED); }
204
205 #ifndef NDEBUG
206   TraceFlag* trace_flag_;
207 #endif
208   Atomic<Value> value_;
209 };
210
211 // A base class for reference-counted objects.
212 // New objects should be created via New() and start with a refcount of 1.
213 // When the refcount reaches 0, the object will be deleted via Delete().
214 //
215 // This will commonly be used by CRTP (curiously-recurring template pattern)
216 // e.g., class MyClass : public RefCounted<MyClass>
217 //
218 // Use PolymorphicRefCount and NonPolymorphicRefCount to select between
219 // different implementations of RefCounted.
220 //
221 // Note that NonPolymorphicRefCount does not support polymorphic destruction.
222 // So, use NonPolymorphicRefCount only when both of the following conditions
223 // are guaranteed to hold:
224 // (a) Child is a concrete leaf class in RefCounted<Child>, and
225 // (b) you are guaranteed to call Unref only on concrete leaf classes and not
226 //     their parents.
227 //
228 // The following example is illegal, because calling Unref() will not call
229 // the dtor of Child.
230 //
231 //    class Parent : public RefCounted<Parent, NonPolymorphicRefCount> {}
232 //    class Child : public Parent {}
233 //
234 //    Child* ch;
235 //    ch->Unref();
236 //
237 template <typename Child, typename Impl = PolymorphicRefCount>
238 class RefCounted : public Impl {
239  public:
240   RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT {
241     IncrementRefCount();
242     return RefCountedPtr<Child>(static_cast<Child*>(this));
243   }
244
245   RefCountedPtr<Child> Ref(const DebugLocation& location,
246                            const char* reason) GRPC_MUST_USE_RESULT {
247     IncrementRefCount(location, reason);
248     return RefCountedPtr<Child>(static_cast<Child*>(this));
249   }
250
251   // TODO(roth): Once all of our code is converted to C++ and can use
252   // RefCountedPtr<> instead of manual ref-counting, make this method
253   // private, since it will only be used by RefCountedPtr<>, which is a
254   // friend of this class.
255   void Unref() {
256     if (GPR_UNLIKELY(refs_.Unref())) {
257       Delete(static_cast<Child*>(this));
258     }
259   }
260   void Unref(const DebugLocation& location, const char* reason) {
261     if (GPR_UNLIKELY(refs_.Unref(location, reason))) {
262       Delete(static_cast<Child*>(this));
263     }
264   }
265
266   bool RefIfNonZero() { return refs_.RefIfNonZero(); }
267   bool RefIfNonZero(const DebugLocation& location, const char* reason) {
268     return refs_.RefIfNonZero(location, reason);
269   }
270
271   // Not copyable nor movable.
272   RefCounted(const RefCounted&) = delete;
273   RefCounted& operator=(const RefCounted&) = delete;
274
275   GRPC_ABSTRACT_BASE_CLASS
276
277  protected:
278   GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
279
280   // TraceFlagT is defined to accept both DebugOnlyTraceFlag and TraceFlag.
281   // Note: RefCount tracing is only enabled on debug builds, even when a
282   //       TraceFlag is used.
283   template <typename TraceFlagT = TraceFlag>
284   explicit RefCounted(TraceFlagT* trace_flag = nullptr,
285                       intptr_t initial_refcount = 1)
286       : refs_(initial_refcount, trace_flag) {}
287
288   // Note: Depending on the Impl used, this dtor can be implicitly virtual.
289   ~RefCounted() = default;
290
291  private:
292   // Allow RefCountedPtr<> to access IncrementRefCount().
293   template <typename T>
294   friend class RefCountedPtr;
295
296   void IncrementRefCount() { refs_.Ref(); }
297   void IncrementRefCount(const DebugLocation& location, const char* reason) {
298     refs_.Ref(location, reason);
299   }
300
301   RefCount refs_;
302 };
303
304 }  // namespace grpc_core
305
306 #endif /* GRPC_CORE_LIB_GPRPP_REF_COUNTED_H */