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