Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 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 | |
Mark D. Roth | 4f2b0fd | 2018-01-19 12:12:23 -0800 | [diff] [blame] | 19 | #ifndef GRPC_CORE_LIB_GPRPP_REF_COUNTED_H |
| 20 | #define GRPC_CORE_LIB_GPRPP_REF_COUNTED_H |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 21 | |
Mark D. Roth | b319f49 | 2017-11-28 14:50:07 -0800 | [diff] [blame] | 22 | #include <grpc/support/log.h> |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 23 | #include <grpc/support/sync.h> |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 24 | |
| 25 | #include "src/core/lib/debug/trace.h" |
Mark D. Roth | 4f2b0fd | 2018-01-19 12:12:23 -0800 | [diff] [blame] | 26 | #include "src/core/lib/gprpp/abstract.h" |
| 27 | #include "src/core/lib/gprpp/debug_location.h" |
| 28 | #include "src/core/lib/gprpp/memory.h" |
Mark D. Roth | 08d9f3d | 2018-02-06 07:58:17 -0800 | [diff] [blame] | 29 | #include "src/core/lib/gprpp/ref_counted_ptr.h" |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 30 | |
| 31 | namespace grpc_core { |
| 32 | |
Mark D. Roth | b319f49 | 2017-11-28 14:50:07 -0800 | [diff] [blame] | 33 | // A base class for reference-counted objects. |
| 34 | // New objects should be created via New() and start with a refcount of 1. |
| 35 | // When the refcount reaches 0, the object will be deleted via Delete(). |
Mark D. Roth | 08d9f3d | 2018-02-06 07:58:17 -0800 | [diff] [blame] | 36 | // |
| 37 | // This will commonly be used by CRTP (curiously-recurring template pattern) |
| 38 | // e.g., class MyClass : public RefCounted<MyClass> |
| 39 | template <typename Child> |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 40 | class RefCounted { |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 41 | public: |
Mark D. Roth | 08d9f3d | 2018-02-06 07:58:17 -0800 | [diff] [blame] | 42 | RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT { |
| 43 | IncrementRefCount(); |
| 44 | return RefCountedPtr<Child>(reinterpret_cast<Child*>(this)); |
| 45 | } |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 46 | |
Mark D. Roth | 08d9f3d | 2018-02-06 07:58:17 -0800 | [diff] [blame] | 47 | // TODO(roth): Once all of our code is converted to C++ and can use |
| 48 | // RefCountedPtr<> instead of manual ref-counting, make this method |
| 49 | // private, since it will only be used by RefCountedPtr<>, which is a |
| 50 | // friend of this class. |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 51 | void Unref() { |
| 52 | if (gpr_unref(&refs_)) { |
| 53 | Delete(this); |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | // Not copyable nor movable. |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 58 | RefCounted(const RefCounted&) = delete; |
| 59 | RefCounted& operator=(const RefCounted&) = delete; |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 60 | |
Mark D. Roth | 324703d | 2018-01-11 07:41:31 -0800 | [diff] [blame] | 61 | GRPC_ABSTRACT_BASE_CLASS |
| 62 | |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 63 | protected: |
| 64 | // Allow Delete() to access destructor. |
| 65 | template <typename T> |
| 66 | friend void Delete(T*); |
| 67 | |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 68 | RefCounted() { gpr_ref_init(&refs_, 1); } |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 69 | |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 70 | virtual ~RefCounted() {} |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 71 | |
| 72 | private: |
Mark D. Roth | 08d9f3d | 2018-02-06 07:58:17 -0800 | [diff] [blame] | 73 | // Allow RefCountedPtr<> to access IncrementRefCount(). |
| 74 | friend class RefCountedPtr<Child>; |
| 75 | |
| 76 | void IncrementRefCount() { gpr_ref(&refs_); } |
| 77 | |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 78 | gpr_refcount refs_; |
| 79 | }; |
| 80 | |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 81 | // An alternative version of the RefCounted base class that |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 82 | // supports tracing. This is intended to be used in cases where the |
| 83 | // object will be handled both by idiomatic C++ code using smart |
| 84 | // pointers and legacy code that is manually calling Ref() and Unref(). |
| 85 | // Once all of our code is converted to idiomatic C++, we may be able to |
| 86 | // eliminate this class. |
Mark D. Roth | 08d9f3d | 2018-02-06 07:58:17 -0800 | [diff] [blame] | 87 | template <typename Child> |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 88 | class RefCountedWithTracing { |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 89 | public: |
Mark D. Roth | 08d9f3d | 2018-02-06 07:58:17 -0800 | [diff] [blame] | 90 | RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT { |
| 91 | IncrementRefCount(); |
| 92 | return RefCountedPtr<Child>(reinterpret_cast<Child*>(this)); |
| 93 | } |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 94 | |
Mark D. Roth | 08d9f3d | 2018-02-06 07:58:17 -0800 | [diff] [blame] | 95 | RefCountedPtr<Child> Ref(const DebugLocation& location, |
| 96 | const char* reason) GRPC_MUST_USE_RESULT { |
Mark D. Roth | b319f49 | 2017-11-28 14:50:07 -0800 | [diff] [blame] | 97 | if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) { |
| 98 | gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count); |
| 99 | gpr_log(GPR_DEBUG, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s", |
| 100 | trace_flag_->name(), this, location.file(), location.line(), |
| 101 | old_refs, old_refs + 1, reason); |
| 102 | } |
Mark D. Roth | 08d9f3d | 2018-02-06 07:58:17 -0800 | [diff] [blame] | 103 | return Ref(); |
Mark D. Roth | b319f49 | 2017-11-28 14:50:07 -0800 | [diff] [blame] | 104 | } |
| 105 | |
Mark D. Roth | 08d9f3d | 2018-02-06 07:58:17 -0800 | [diff] [blame] | 106 | // TODO(roth): Once all of our code is converted to C++ and can use |
| 107 | // RefCountedPtr<> instead of manual ref-counting, make the Unref() methods |
| 108 | // private, since they will only be used by RefCountedPtr<>, which is a |
| 109 | // friend of this class. |
| 110 | |
Mark D. Roth | b319f49 | 2017-11-28 14:50:07 -0800 | [diff] [blame] | 111 | void Unref() { |
| 112 | if (gpr_unref(&refs_)) { |
| 113 | Delete(this); |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | void Unref(const DebugLocation& location, const char* reason) { |
| 118 | if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) { |
| 119 | gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count); |
| 120 | gpr_log(GPR_DEBUG, "%s:%p %s:%d unref %" PRIdPTR " -> %" PRIdPTR " %s", |
| 121 | trace_flag_->name(), this, location.file(), location.line(), |
| 122 | old_refs, old_refs - 1, reason); |
| 123 | } |
| 124 | Unref(); |
| 125 | } |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 126 | |
| 127 | // Not copyable nor movable. |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 128 | RefCountedWithTracing(const RefCountedWithTracing&) = delete; |
| 129 | RefCountedWithTracing& operator=(const RefCountedWithTracing&) = delete; |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 130 | |
Mark D. Roth | 324703d | 2018-01-11 07:41:31 -0800 | [diff] [blame] | 131 | GRPC_ABSTRACT_BASE_CLASS |
| 132 | |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 133 | protected: |
Mark D. Roth | abadc6c | 2017-11-28 08:24:10 -0800 | [diff] [blame] | 134 | // Allow Delete() to access destructor. |
Mark D. Roth | d3984c3 | 2017-11-28 09:13:27 -0800 | [diff] [blame] | 135 | template <typename T> |
Mark D. Roth | abadc6c | 2017-11-28 08:24:10 -0800 | [diff] [blame] | 136 | friend void Delete(T*); |
| 137 | |
Mark D. Roth | 324703d | 2018-01-11 07:41:31 -0800 | [diff] [blame] | 138 | RefCountedWithTracing() |
| 139 | : RefCountedWithTracing(static_cast<TraceFlag*>(nullptr)) {} |
Mark D. Roth | b319f49 | 2017-11-28 14:50:07 -0800 | [diff] [blame] | 140 | |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 141 | explicit RefCountedWithTracing(TraceFlag* trace_flag) |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 142 | : trace_flag_(trace_flag) { |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 143 | gpr_ref_init(&refs_, 1); |
| 144 | } |
| 145 | |
Mark D. Roth | 324703d | 2018-01-11 07:41:31 -0800 | [diff] [blame] | 146 | #ifdef NDEBUG |
| 147 | explicit RefCountedWithTracing(DebugOnlyTraceFlag* trace_flag) |
| 148 | : RefCountedWithTracing() {} |
| 149 | #endif |
| 150 | |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 151 | virtual ~RefCountedWithTracing() {} |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 152 | |
| 153 | private: |
Mark D. Roth | 08d9f3d | 2018-02-06 07:58:17 -0800 | [diff] [blame] | 154 | // Allow RefCountedPtr<> to access IncrementRefCount(). |
| 155 | friend class RefCountedPtr<Child>; |
| 156 | |
| 157 | void IncrementRefCount() { gpr_ref(&refs_); } |
| 158 | |
Mark D. Roth | b319f49 | 2017-11-28 14:50:07 -0800 | [diff] [blame] | 159 | TraceFlag* trace_flag_ = nullptr; |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 160 | gpr_refcount refs_; |
| 161 | }; |
| 162 | |
| 163 | } // namespace grpc_core |
| 164 | |
Mark D. Roth | 4f2b0fd | 2018-01-19 12:12:23 -0800 | [diff] [blame] | 165 | #endif /* GRPC_CORE_LIB_GPRPP_REF_COUNTED_H */ |