blob: 50199730c90b43e2670447572b47d255d30e5f60 [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. Roth324703d2018-01-11 07:41:31 -080031
32namespace grpc_core {
33
Mark D. Roth2b19f492018-01-16 15:10:27 -080034// A base class for orphanable objects, which have one external owner
35// but are not necessarily destroyed immediately when the external owner
36// gives up ownership. Instead, the owner calls the object's Orphan()
37// method, and the object then takes responsibility for its own cleanup
38// and destruction.
Mark D. Roth324703d2018-01-11 07:41:31 -080039class Orphanable {
40 public:
41 // Gives up ownership of the object. The implementation must arrange
Mark D. Roth2b19f492018-01-16 15:10:27 -080042 // to eventually destroy the object without further interaction from the
43 // caller.
Mark D. Roth324703d2018-01-11 07:41:31 -080044 virtual void Orphan() GRPC_ABSTRACT;
45
46 // Not copyable or movable.
47 Orphanable(const Orphanable&) = delete;
48 Orphanable& operator=(const Orphanable&) = delete;
49
50 GRPC_ABSTRACT_BASE_CLASS
51
52 protected:
53 Orphanable() {}
54 virtual ~Orphanable() {}
55};
56
57template <typename T>
58class OrphanableDelete {
59 public:
60 void operator()(T* p) { p->Orphan(); }
61};
62
63template <typename T, typename Deleter = OrphanableDelete<T>>
64using OrphanablePtr = std::unique_ptr<T, Deleter>;
65
66template <typename T, typename... Args>
67inline OrphanablePtr<T> MakeOrphanable(Args&&... args) {
68 return OrphanablePtr<T>(New<T>(std::forward<Args>(args)...));
69}
70
71// A type of Orphanable with internal ref-counting.
72class InternallyRefCounted : public Orphanable {
73 public:
74 // Not copyable nor movable.
75 InternallyRefCounted(const InternallyRefCounted&) = delete;
76 InternallyRefCounted& operator=(const InternallyRefCounted&) = delete;
77
78 GRPC_ABSTRACT_BASE_CLASS
79
80 protected:
81 InternallyRefCounted() { gpr_ref_init(&refs_, 1); }
82 virtual ~InternallyRefCounted() {}
83
84 void Ref() { gpr_ref(&refs_); }
85
86 void Unref() {
87 if (gpr_unref(&refs_)) {
88 Delete(this);
89 }
90 }
91
92 // Allow Delete() to access destructor.
93 template <typename T>
94 friend void Delete(T*);
95
96 private:
97 gpr_refcount refs_;
98};
99
100// An alternative version of the InternallyRefCounted base class that
101// supports tracing. This is intended to be used in cases where the
102// object will be handled both by idiomatic C++ code using smart
103// pointers and legacy code that is manually calling Ref() and Unref().
104// Once all of our code is converted to idiomatic C++, we may be able to
105// eliminate this class.
106class InternallyRefCountedWithTracing : public Orphanable {
107 public:
108 // Not copyable nor movable.
109 InternallyRefCountedWithTracing(const InternallyRefCountedWithTracing&) =
110 delete;
111 InternallyRefCountedWithTracing& operator=(
112 const InternallyRefCountedWithTracing&) = delete;
113
114 GRPC_ABSTRACT_BASE_CLASS
115
116 protected:
117 // Allow Delete() to access destructor.
118 template <typename T>
119 friend void Delete(T*);
120
121 InternallyRefCountedWithTracing()
122 : InternallyRefCountedWithTracing(static_cast<TraceFlag*>(nullptr)) {}
123
124 explicit InternallyRefCountedWithTracing(TraceFlag* trace_flag)
125 : trace_flag_(trace_flag) {
126 gpr_ref_init(&refs_, 1);
127 }
128
129#ifdef NDEBUG
130 explicit InternallyRefCountedWithTracing(DebugOnlyTraceFlag* trace_flag)
131 : InternallyRefCountedWithTracing() {}
132#endif
133
134 virtual ~InternallyRefCountedWithTracing() {}
135
136 void Ref() { gpr_ref(&refs_); }
137
138 void Ref(const DebugLocation& location, const char* reason) {
139 if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
140 gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count);
141 gpr_log(GPR_DEBUG, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s",
142 trace_flag_->name(), this, location.file(), location.line(),
143 old_refs, old_refs + 1, reason);
144 }
145 Ref();
146 }
147
148 void Unref() {
149 if (gpr_unref(&refs_)) {
150 Delete(this);
151 }
152 }
153
154 void Unref(const DebugLocation& location, const char* reason) {
155 if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
156 gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count);
157 gpr_log(GPR_DEBUG, "%s:%p %s:%d unref %" PRIdPTR " -> %" PRIdPTR " %s",
158 trace_flag_->name(), this, location.file(), location.line(),
159 old_refs, old_refs - 1, reason);
160 }
161 Unref();
162 }
163
164 private:
165 TraceFlag* trace_flag_ = nullptr;
166 gpr_refcount refs_;
167};
168
169} // namespace grpc_core
170
Mark D. Roth4f2b0fd2018-01-19 12:12:23 -0800171#endif /* GRPC_CORE_LIB_GPRPP_ORPHANABLE_H */