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 | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 19 | #ifndef GRPC_CORE_LIB_SUPPORT_REF_COUNTED_H |
| 20 | #define GRPC_CORE_LIB_SUPPORT_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 | 324703d | 2018-01-11 07:41:31 -0800 | [diff] [blame^] | 26 | #include "src/core/lib/support/abstract.h" |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 27 | #include "src/core/lib/support/debug_location.h" |
Mark D. Roth | b319f49 | 2017-11-28 14:50:07 -0800 | [diff] [blame] | 28 | #include "src/core/lib/support/memory.h" |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 29 | |
| 30 | namespace grpc_core { |
| 31 | |
Mark D. Roth | b319f49 | 2017-11-28 14:50:07 -0800 | [diff] [blame] | 32 | // A base class for reference-counted objects. |
| 33 | // New objects should be created via New() and start with a refcount of 1. |
| 34 | // When the refcount reaches 0, the object will be deleted via Delete(). |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 35 | class RefCounted { |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 36 | public: |
Mark D. Roth | b319f49 | 2017-11-28 14:50:07 -0800 | [diff] [blame] | 37 | void Ref() { gpr_ref(&refs_); } |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 38 | |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 39 | void Unref() { |
| 40 | if (gpr_unref(&refs_)) { |
| 41 | Delete(this); |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | // Not copyable nor movable. |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 46 | RefCounted(const RefCounted&) = delete; |
| 47 | RefCounted& operator=(const RefCounted&) = delete; |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 48 | |
Mark D. Roth | 324703d | 2018-01-11 07:41:31 -0800 | [diff] [blame^] | 49 | GRPC_ABSTRACT_BASE_CLASS |
| 50 | |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 51 | protected: |
| 52 | // Allow Delete() to access destructor. |
| 53 | template <typename T> |
| 54 | friend void Delete(T*); |
| 55 | |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 56 | RefCounted() { gpr_ref_init(&refs_, 1); } |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 57 | |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 58 | virtual ~RefCounted() {} |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 59 | |
| 60 | private: |
| 61 | gpr_refcount refs_; |
| 62 | }; |
| 63 | |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 64 | // An alternative version of the RefCounted base class that |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 65 | // supports tracing. This is intended to be used in cases where the |
| 66 | // object will be handled both by idiomatic C++ code using smart |
| 67 | // pointers and legacy code that is manually calling Ref() and Unref(). |
| 68 | // Once all of our code is converted to idiomatic C++, we may be able to |
| 69 | // eliminate this class. |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 70 | class RefCountedWithTracing { |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 71 | public: |
| 72 | void Ref() { gpr_ref(&refs_); } |
| 73 | |
Mark D. Roth | b319f49 | 2017-11-28 14:50:07 -0800 | [diff] [blame] | 74 | void Ref(const DebugLocation& location, const char* reason) { |
| 75 | if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) { |
| 76 | gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count); |
| 77 | gpr_log(GPR_DEBUG, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s", |
| 78 | trace_flag_->name(), this, location.file(), location.line(), |
| 79 | old_refs, old_refs + 1, reason); |
| 80 | } |
| 81 | Ref(); |
| 82 | } |
| 83 | |
| 84 | void Unref() { |
| 85 | if (gpr_unref(&refs_)) { |
| 86 | Delete(this); |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | void Unref(const DebugLocation& location, const char* reason) { |
| 91 | if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) { |
| 92 | gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count); |
| 93 | gpr_log(GPR_DEBUG, "%s:%p %s:%d unref %" PRIdPTR " -> %" PRIdPTR " %s", |
| 94 | trace_flag_->name(), this, location.file(), location.line(), |
| 95 | old_refs, old_refs - 1, reason); |
| 96 | } |
| 97 | Unref(); |
| 98 | } |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 99 | |
| 100 | // Not copyable nor movable. |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 101 | RefCountedWithTracing(const RefCountedWithTracing&) = delete; |
| 102 | RefCountedWithTracing& operator=(const RefCountedWithTracing&) = delete; |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 103 | |
Mark D. Roth | 324703d | 2018-01-11 07:41:31 -0800 | [diff] [blame^] | 104 | GRPC_ABSTRACT_BASE_CLASS |
| 105 | |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 106 | protected: |
Mark D. Roth | abadc6c | 2017-11-28 08:24:10 -0800 | [diff] [blame] | 107 | // Allow Delete() to access destructor. |
Mark D. Roth | d3984c3 | 2017-11-28 09:13:27 -0800 | [diff] [blame] | 108 | template <typename T> |
Mark D. Roth | abadc6c | 2017-11-28 08:24:10 -0800 | [diff] [blame] | 109 | friend void Delete(T*); |
| 110 | |
Mark D. Roth | 324703d | 2018-01-11 07:41:31 -0800 | [diff] [blame^] | 111 | RefCountedWithTracing() |
| 112 | : RefCountedWithTracing(static_cast<TraceFlag*>(nullptr)) {} |
Mark D. Roth | b319f49 | 2017-11-28 14:50:07 -0800 | [diff] [blame] | 113 | |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 114 | explicit RefCountedWithTracing(TraceFlag* trace_flag) |
Mark D. Roth | 853fff8 | 2017-11-29 07:37:41 -0800 | [diff] [blame] | 115 | : trace_flag_(trace_flag) { |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 116 | gpr_ref_init(&refs_, 1); |
| 117 | } |
| 118 | |
Mark D. Roth | 324703d | 2018-01-11 07:41:31 -0800 | [diff] [blame^] | 119 | #ifdef NDEBUG |
| 120 | explicit RefCountedWithTracing(DebugOnlyTraceFlag* trace_flag) |
| 121 | : RefCountedWithTracing() {} |
| 122 | #endif |
| 123 | |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 124 | virtual ~RefCountedWithTracing() {} |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 125 | |
| 126 | private: |
Mark D. Roth | b319f49 | 2017-11-28 14:50:07 -0800 | [diff] [blame] | 127 | TraceFlag* trace_flag_ = nullptr; |
Mark D. Roth | 70db663 | 2017-11-27 14:53:26 -0800 | [diff] [blame] | 128 | gpr_refcount refs_; |
| 129 | }; |
| 130 | |
| 131 | } // namespace grpc_core |
| 132 | |
Mark D. Roth | bf816d3 | 2017-11-29 11:25:34 -0800 | [diff] [blame] | 133 | #endif /* GRPC_CORE_LIB_SUPPORT_REF_COUNTED_H */ |