blob: c68118a71a615da1150fc6d564c22c6ad1be7be5 [file] [log] [blame]
Mark D. Roth70db6632017-11-27 14:53:26 -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_REF_COUNTED_H
20#define GRPC_CORE_LIB_GPRPP_REF_COUNTED_H
Mark D. Roth70db6632017-11-27 14:53:26 -080021
Mark D. Rothb319f492017-11-28 14:50:07 -080022#include <grpc/support/log.h>
Mark D. Roth853fff82017-11-29 07:37:41 -080023#include <grpc/support/sync.h>
Mark D. Roth70db6632017-11-27 14:53:26 -080024
25#include "src/core/lib/debug/trace.h"
Mark D. Roth4f2b0fd2018-01-19 12:12:23 -080026#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. Roth70db6632017-11-27 14:53:26 -080029
30namespace grpc_core {
31
Mark D. Rothb319f492017-11-28 14:50:07 -080032// 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. Rothbf816d32017-11-29 11:25:34 -080035class RefCounted {
Mark D. Roth70db6632017-11-27 14:53:26 -080036 public:
Mark D. Rothb319f492017-11-28 14:50:07 -080037 void Ref() { gpr_ref(&refs_); }
Mark D. Roth70db6632017-11-27 14:53:26 -080038
Mark D. Roth853fff82017-11-29 07:37:41 -080039 void Unref() {
40 if (gpr_unref(&refs_)) {
41 Delete(this);
42 }
43 }
44
45 // Not copyable nor movable.
Mark D. Rothbf816d32017-11-29 11:25:34 -080046 RefCounted(const RefCounted&) = delete;
47 RefCounted& operator=(const RefCounted&) = delete;
Mark D. Roth853fff82017-11-29 07:37:41 -080048
Mark D. Roth324703d2018-01-11 07:41:31 -080049 GRPC_ABSTRACT_BASE_CLASS
50
Mark D. Roth853fff82017-11-29 07:37:41 -080051 protected:
52 // Allow Delete() to access destructor.
53 template <typename T>
54 friend void Delete(T*);
55
Mark D. Rothbf816d32017-11-29 11:25:34 -080056 RefCounted() { gpr_ref_init(&refs_, 1); }
Mark D. Roth853fff82017-11-29 07:37:41 -080057
Mark D. Rothbf816d32017-11-29 11:25:34 -080058 virtual ~RefCounted() {}
Mark D. Roth853fff82017-11-29 07:37:41 -080059
60 private:
61 gpr_refcount refs_;
62};
63
Mark D. Rothbf816d32017-11-29 11:25:34 -080064// An alternative version of the RefCounted base class that
Mark D. Roth853fff82017-11-29 07:37:41 -080065// 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. Rothbf816d32017-11-29 11:25:34 -080070class RefCountedWithTracing {
Mark D. Roth853fff82017-11-29 07:37:41 -080071 public:
72 void Ref() { gpr_ref(&refs_); }
73
Mark D. Rothb319f492017-11-28 14:50:07 -080074 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. Roth70db6632017-11-27 14:53:26 -080099
100 // Not copyable nor movable.
Mark D. Rothbf816d32017-11-29 11:25:34 -0800101 RefCountedWithTracing(const RefCountedWithTracing&) = delete;
102 RefCountedWithTracing& operator=(const RefCountedWithTracing&) = delete;
Mark D. Roth70db6632017-11-27 14:53:26 -0800103
Mark D. Roth324703d2018-01-11 07:41:31 -0800104 GRPC_ABSTRACT_BASE_CLASS
105
Mark D. Roth70db6632017-11-27 14:53:26 -0800106 protected:
Mark D. Rothabadc6c2017-11-28 08:24:10 -0800107 // Allow Delete() to access destructor.
Mark D. Rothd3984c32017-11-28 09:13:27 -0800108 template <typename T>
Mark D. Rothabadc6c2017-11-28 08:24:10 -0800109 friend void Delete(T*);
110
Mark D. Roth324703d2018-01-11 07:41:31 -0800111 RefCountedWithTracing()
112 : RefCountedWithTracing(static_cast<TraceFlag*>(nullptr)) {}
Mark D. Rothb319f492017-11-28 14:50:07 -0800113
Mark D. Rothbf816d32017-11-29 11:25:34 -0800114 explicit RefCountedWithTracing(TraceFlag* trace_flag)
Mark D. Roth853fff82017-11-29 07:37:41 -0800115 : trace_flag_(trace_flag) {
Mark D. Roth70db6632017-11-27 14:53:26 -0800116 gpr_ref_init(&refs_, 1);
117 }
118
Mark D. Roth324703d2018-01-11 07:41:31 -0800119#ifdef NDEBUG
120 explicit RefCountedWithTracing(DebugOnlyTraceFlag* trace_flag)
121 : RefCountedWithTracing() {}
122#endif
123
Mark D. Rothbf816d32017-11-29 11:25:34 -0800124 virtual ~RefCountedWithTracing() {}
Mark D. Roth70db6632017-11-27 14:53:26 -0800125
126 private:
Mark D. Rothb319f492017-11-28 14:50:07 -0800127 TraceFlag* trace_flag_ = nullptr;
Mark D. Roth70db6632017-11-27 14:53:26 -0800128 gpr_refcount refs_;
129};
130
131} // namespace grpc_core
132
Mark D. Roth4f2b0fd2018-01-19 12:12:23 -0800133#endif /* GRPC_CORE_LIB_GPRPP_REF_COUNTED_H */