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_ORPHANABLE_H 20 #define GRPC_CORE_LIB_GPRPP_ORPHANABLE_H 21 22 #include <grpc/support/port_platform.h> 23 24 #include <grpc/support/log.h> 25 #include <grpc/support/sync.h> 26 27 #include <cinttypes> 28 #include <memory> 29 30 #include "src/core/lib/debug/trace.h" 31 #include "src/core/lib/gprpp/abstract.h" 32 #include "src/core/lib/gprpp/debug_location.h" 33 #include "src/core/lib/gprpp/memory.h" 34 #include "src/core/lib/gprpp/ref_counted_ptr.h" 35 36 namespace grpc_core { 37 38 // A base class for orphanable objects, which have one external owner 39 // but are not necessarily destroyed immediately when the external owner 40 // gives up ownership. Instead, the owner calls the object's Orphan() 41 // method, and the object then takes responsibility for its own cleanup 42 // and destruction. 43 class Orphanable { 44 public: 45 // Gives up ownership of the object. The implementation must arrange 46 // to eventually destroy the object without further interaction from the 47 // caller. 48 virtual void Orphan() GRPC_ABSTRACT; 49 50 // Not copyable or movable. 51 Orphanable(const Orphanable&) = delete; 52 Orphanable& operator=(const Orphanable&) = delete; 53 54 GRPC_ABSTRACT_BASE_CLASS 55 56 protected: 57 Orphanable() {} 58 virtual ~Orphanable() {} 59 }; 60 61 template <typename T> 62 class OrphanableDelete { 63 public: 64 void operator()(T* p) { p->Orphan(); } 65 }; 66 67 template <typename T, typename Deleter = OrphanableDelete<T>> 68 using OrphanablePtr = std::unique_ptr<T, Deleter>; 69 70 template <typename T, typename... Args> 71 inline OrphanablePtr<T> MakeOrphanable(Args&&... args) { 72 return OrphanablePtr<T>(New<T>(std::forward<Args>(args)...)); 73 } 74 75 // A type of Orphanable with internal ref-counting. 76 template <typename Child> 77 class InternallyRefCounted : public Orphanable { 78 public: 79 // Not copyable nor movable. 80 InternallyRefCounted(const InternallyRefCounted&) = delete; 81 InternallyRefCounted& operator=(const InternallyRefCounted&) = delete; 82 83 GRPC_ABSTRACT_BASE_CLASS 84 85 protected: 86 GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE 87 88 // Allow RefCountedPtr<> to access Unref() and IncrementRefCount(). 89 template <typename T> 90 friend class RefCountedPtr; 91 92 InternallyRefCounted() { gpr_ref_init(&refs_, 1); } 93 virtual ~InternallyRefCounted() {} 94 95 RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT { 96 IncrementRefCount(); 97 return RefCountedPtr<Child>(static_cast<Child*>(this)); 98 } 99 100 void Unref() { 101 if (gpr_unref(&refs_)) { 102 Delete(static_cast<Child*>(this)); 103 } 104 } 105 106 private: 107 void IncrementRefCount() { gpr_ref(&refs_); } 108 109 gpr_refcount refs_; 110 }; 111 112 // An alternative version of the InternallyRefCounted base class that 113 // supports tracing. This is intended to be used in cases where the 114 // object will be handled both by idiomatic C++ code using smart 115 // pointers and legacy code that is manually calling Ref() and Unref(). 116 // Once all of our code is converted to idiomatic C++, we may be able to 117 // eliminate this class. 118 template <typename Child> 119 class InternallyRefCountedWithTracing : public Orphanable { 120 public: 121 // Not copyable nor movable. 122 InternallyRefCountedWithTracing(const InternallyRefCountedWithTracing&) = 123 delete; 124 InternallyRefCountedWithTracing& operator=( 125 const InternallyRefCountedWithTracing&) = delete; 126 127 GRPC_ABSTRACT_BASE_CLASS 128 129 protected: 130 GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE 131 132 // Allow RefCountedPtr<> to access Unref() and IncrementRefCount(). 133 template <typename T> 134 friend class RefCountedPtr; 135 136 InternallyRefCountedWithTracing() 137 : InternallyRefCountedWithTracing(static_cast<TraceFlag*>(nullptr)) {} 138 139 explicit InternallyRefCountedWithTracing(TraceFlag* trace_flag) 140 : trace_flag_(trace_flag) { 141 gpr_ref_init(&refs_, 1); 142 } 143 144 #ifdef NDEBUG 145 explicit InternallyRefCountedWithTracing(DebugOnlyTraceFlag* trace_flag) 146 : InternallyRefCountedWithTracing() {} 147 #endif 148 149 virtual ~InternallyRefCountedWithTracing() {} 150 151 RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT { 152 IncrementRefCount(); 153 return RefCountedPtr<Child>(static_cast<Child*>(this)); 154 } 155 156 RefCountedPtr<Child> Ref(const DebugLocation& location, 157 const char* reason) GRPC_MUST_USE_RESULT { 158 if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) { 159 gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count); 160 gpr_log(GPR_INFO, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s", 161 trace_flag_->name(), this, location.file(), location.line(), 162 old_refs, old_refs + 1, reason); 163 } 164 return Ref(); 165 } 166 167 // TODO(roth): Once all of our code is converted to C++ and can use 168 // RefCountedPtr<> instead of manual ref-counting, make the Unref() methods 169 // private, since they will only be used by RefCountedPtr<>, which is a 170 // friend of this class. 171 172 void Unref() { 173 if (gpr_unref(&refs_)) { 174 Delete(static_cast<Child*>(this)); 175 } 176 } 177 178 void Unref(const DebugLocation& location, const char* reason) { 179 if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) { 180 gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count); 181 gpr_log(GPR_INFO, "%s:%p %s:%d unref %" PRIdPTR " -> %" PRIdPTR " %s", 182 trace_flag_->name(), this, location.file(), location.line(), 183 old_refs, old_refs - 1, reason); 184 } 185 Unref(); 186 } 187 188 private: 189 void IncrementRefCount() { gpr_ref(&refs_); } 190 191 TraceFlag* trace_flag_ = nullptr; 192 gpr_refcount refs_; 193 }; 194 195 } // namespace grpc_core 196 197 #endif /* GRPC_CORE_LIB_GPRPP_ORPHANABLE_H */ 198