blob: 6e127c2861dd2e36edc09fdd9a0aedd006d81023 [file] [log] [blame]
Mark D. Roth324703d2018-01-11 07:41:31 -08001/*
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
Mark D. Roth4f2b0fd2018-01-19 12:12:23 -080019#ifndef GRPC_CORE_LIB_GPRPP_ORPHANABLE_H
20#define GRPC_CORE_LIB_GPRPP_ORPHANABLE_H
Mark D. Roth324703d2018-01-11 07:41:31 -080021
22#include <grpc/support/log.h>
23#include <grpc/support/sync.h>
24
25#include <memory>
26
27#include "src/core/lib/debug/trace.h"
Mark D. Roth4f2b0fd2018-01-19 12:12:23 -080028#include "src/core/lib/gprpp/abstract.h"
29#include "src/core/lib/gprpp/debug_location.h"
30#include "src/core/lib/gprpp/memory.h"
Mark D. Roth08d9f3d2018-02-06 07:58:17 -080031#include "src/core/lib/gprpp/ref_counted_ptr.h"
Mark D. Roth324703d2018-01-11 07:41:31 -080032
33namespace grpc_core {
34
Mark D. Roth2b19f492018-01-16 15:10:27 -080035// A base class for orphanable objects, which have one external owner
36// but are not necessarily destroyed immediately when the external owner
37// gives up ownership. Instead, the owner calls the object's Orphan()
38// method, and the object then takes responsibility for its own cleanup
39// and destruction.
Mark D. Roth324703d2018-01-11 07:41:31 -080040class Orphanable {
41 public:
42 // Gives up ownership of the object. The implementation must arrange
Mark D. Roth2b19f492018-01-16 15:10:27 -080043 // to eventually destroy the object without further interaction from the
44 // caller.
Mark D. Roth324703d2018-01-11 07:41:31 -080045 virtual void Orphan() GRPC_ABSTRACT;
46
47 // Not copyable or movable.
48 Orphanable(const Orphanable&) = delete;
49 Orphanable& operator=(const Orphanable&) = delete;
50
51 GRPC_ABSTRACT_BASE_CLASS
52
53 protected:
54 Orphanable() {}
55 virtual ~Orphanable() {}
56};
57
58template <typename T>
59class OrphanableDelete {
60 public:
61 void operator()(T* p) { p->Orphan(); }
62};
63
64template <typename T, typename Deleter = OrphanableDelete<T>>
65using OrphanablePtr = std::unique_ptr<T, Deleter>;
66
67template <typename T, typename... Args>
68inline OrphanablePtr<T> MakeOrphanable(Args&&... args) {
69 return OrphanablePtr<T>(New<T>(std::forward<Args>(args)...));
70}
71
72// A type of Orphanable with internal ref-counting.
Mark D. Roth08d9f3d2018-02-06 07:58:17 -080073template <typename Child>
Mark D. Roth324703d2018-01-11 07:41:31 -080074class InternallyRefCounted : public Orphanable {
75 public:
76 // Not copyable nor movable.
77 InternallyRefCounted(const InternallyRefCounted&) = delete;
78 InternallyRefCounted& operator=(const InternallyRefCounted&) = delete;
79
80 GRPC_ABSTRACT_BASE_CLASS
81
82 protected:
Mark D. Roth08d9f3d2018-02-06 07:58:17 -080083 // Allow Delete() to access destructor.
84 template <typename T>
85 friend void Delete(T*);
86
87 // Allow RefCountedPtr<> to access Unref() and IncrementRefCount().
88 friend class RefCountedPtr<Child>;
89
Mark D. Roth324703d2018-01-11 07:41:31 -080090 InternallyRefCounted() { gpr_ref_init(&refs_, 1); }
91 virtual ~InternallyRefCounted() {}
92
Mark D. Roth08d9f3d2018-02-06 07:58:17 -080093 RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT {
94 IncrementRefCount();
95 return RefCountedPtr<Child>(reinterpret_cast<Child*>(this));
96 }
Mark D. Roth324703d2018-01-11 07:41:31 -080097
98 void Unref() {
99 if (gpr_unref(&refs_)) {
100 Delete(this);
101 }
102 }
103
Mark D. Roth324703d2018-01-11 07:41:31 -0800104 private:
Mark D. Roth08d9f3d2018-02-06 07:58:17 -0800105 void IncrementRefCount() { gpr_ref(&refs_); }
106
Mark D. Roth324703d2018-01-11 07:41:31 -0800107 gpr_refcount refs_;
108};
109
110// An alternative version of the InternallyRefCounted base class that
111// supports tracing. This is intended to be used in cases where the
112// object will be handled both by idiomatic C++ code using smart
113// pointers and legacy code that is manually calling Ref() and Unref().
114// Once all of our code is converted to idiomatic C++, we may be able to
115// eliminate this class.
Mark D. Roth08d9f3d2018-02-06 07:58:17 -0800116template <typename Child>
Mark D. Roth324703d2018-01-11 07:41:31 -0800117class InternallyRefCountedWithTracing : public Orphanable {
118 public:
119 // Not copyable nor movable.
120 InternallyRefCountedWithTracing(const InternallyRefCountedWithTracing&) =
121 delete;
122 InternallyRefCountedWithTracing& operator=(
123 const InternallyRefCountedWithTracing&) = delete;
124
125 GRPC_ABSTRACT_BASE_CLASS
126
127 protected:
128 // Allow Delete() to access destructor.
129 template <typename T>
130 friend void Delete(T*);
131
Mark D. Roth08d9f3d2018-02-06 07:58:17 -0800132 // Allow RefCountedPtr<> to access Unref() and IncrementRefCount().
133 friend class RefCountedPtr<Child>;
134
Mark D. Roth324703d2018-01-11 07:41:31 -0800135 InternallyRefCountedWithTracing()
136 : InternallyRefCountedWithTracing(static_cast<TraceFlag*>(nullptr)) {}
137
138 explicit InternallyRefCountedWithTracing(TraceFlag* trace_flag)
139 : trace_flag_(trace_flag) {
140 gpr_ref_init(&refs_, 1);
141 }
142
143#ifdef NDEBUG
144 explicit InternallyRefCountedWithTracing(DebugOnlyTraceFlag* trace_flag)
145 : InternallyRefCountedWithTracing() {}
146#endif
147
148 virtual ~InternallyRefCountedWithTracing() {}
149
Mark D. Roth08d9f3d2018-02-06 07:58:17 -0800150 RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT {
151 IncrementRefCount();
152 return RefCountedPtr<Child>(reinterpret_cast<Child*>(this));
153 }
Mark D. Roth324703d2018-01-11 07:41:31 -0800154
Mark D. Roth08d9f3d2018-02-06 07:58:17 -0800155 RefCountedPtr<Child> Ref(const DebugLocation& location,
156 const char* reason) GRPC_MUST_USE_RESULT {
Mark D. Roth324703d2018-01-11 07:41:31 -0800157 if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
158 gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count);
159 gpr_log(GPR_DEBUG, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s",
160 trace_flag_->name(), this, location.file(), location.line(),
161 old_refs, old_refs + 1, reason);
162 }
Mark D. Roth08d9f3d2018-02-06 07:58:17 -0800163 return Ref();
Mark D. Roth324703d2018-01-11 07:41:31 -0800164 }
165
Mark D. Roth08d9f3d2018-02-06 07:58:17 -0800166 // TODO(roth): Once all of our code is converted to C++ and can use
167 // RefCountedPtr<> instead of manual ref-counting, make the Unref() methods
168 // private, since they will only be used by RefCountedPtr<>, which is a
169 // friend of this class.
170
Mark D. Roth324703d2018-01-11 07:41:31 -0800171 void Unref() {
172 if (gpr_unref(&refs_)) {
173 Delete(this);
174 }
175 }
176
177 void Unref(const DebugLocation& location, const char* reason) {
178 if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
179 gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count);
180 gpr_log(GPR_DEBUG, "%s:%p %s:%d unref %" PRIdPTR " -> %" PRIdPTR " %s",
181 trace_flag_->name(), this, location.file(), location.line(),
182 old_refs, old_refs - 1, reason);
183 }
184 Unref();
185 }
186
187 private:
Mark D. Roth08d9f3d2018-02-06 07:58:17 -0800188 void IncrementRefCount() { gpr_ref(&refs_); }
189
Mark D. Roth324703d2018-01-11 07:41:31 -0800190 TraceFlag* trace_flag_ = nullptr;
191 gpr_refcount refs_;
192};
193
194} // namespace grpc_core
195
Mark D. Roth4f2b0fd2018-01-19 12:12:23 -0800196#endif /* GRPC_CORE_LIB_GPRPP_ORPHANABLE_H */