Merge pull request #17188 from soheilhy/worktree-refcounted

Add grpc_core::RefCount and use it for RefCountedPtr
pull/17063/head
Soheil Hassas Yeganeh 6 years ago committed by GitHub
commit fdf63a7c02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 73
      src/core/lib/gprpp/ref_counted.h

@ -24,6 +24,8 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <atomic>
#include <cassert>
#include <cinttypes>
#include "src/core/lib/debug/trace.h"
@ -42,7 +44,7 @@ class PolymorphicRefCount {
protected:
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
virtual ~PolymorphicRefCount() {}
virtual ~PolymorphicRefCount() = default;
};
// NonPolymorphicRefCount does not enforce polymorphic destruction of
@ -55,7 +57,48 @@ class NonPolymorphicRefCount {
protected:
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
~NonPolymorphicRefCount() {}
~NonPolymorphicRefCount() = default;
};
// RefCount is a simple atomic ref-count.
//
// This is a C++ implementation of gpr_refcount, with inline functions. Due to
// inline functions, this class is significantly more efficient than
// gpr_refcount and should be preferred over gpr_refcount whenever possible.
//
// TODO(soheil): Remove gpr_refcount after submitting the GRFC and the paragraph
// above.
class RefCount {
public:
using Value = intptr_t;
// `init` is the initial refcount stored in this object.
constexpr explicit RefCount(Value init = 1) : value_(init) {}
// Increases the ref-count by `n`.
void Ref(Value n = 1) { value_.fetch_add(n, std::memory_order_relaxed); }
// Similar to Ref() with an assert on the ref-count being non-zero.
void RefNonZero() {
#ifndef NDEBUG
const Value prior = value_.fetch_add(1, std::memory_order_relaxed);
assert(prior > 0);
#else
Ref();
#endif
}
// Decrements the ref-count and returns true if the ref-count reaches 0.
bool Unref() {
const Value prior = value_.fetch_sub(1, std::memory_order_acq_rel);
GPR_DEBUG_ASSERT(prior > 0);
return prior == 1;
}
Value get() const { return value_.load(std::memory_order_relaxed); }
private:
std::atomic<Value> value_;
};
// A base class for reference-counted objects.
@ -97,7 +140,7 @@ class RefCounted : public Impl {
// private, since it will only be used by RefCountedPtr<>, which is a
// friend of this class.
void Unref() {
if (gpr_unref(&refs_)) {
if (refs_.Unref()) {
Delete(static_cast<Child*>(this));
}
}
@ -111,19 +154,19 @@ class RefCounted : public Impl {
protected:
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
RefCounted() { gpr_ref_init(&refs_, 1); }
RefCounted() = default;
// Note: Depending on the Impl used, this dtor can be implicitly virtual.
~RefCounted() {}
~RefCounted() = default;
private:
// Allow RefCountedPtr<> to access IncrementRefCount().
template <typename T>
friend class RefCountedPtr;
void IncrementRefCount() { gpr_ref(&refs_); }
void IncrementRefCount() { refs_.Ref(); }
gpr_refcount refs_;
RefCount refs_;
};
// An alternative version of the RefCounted base class that
@ -143,7 +186,7 @@ class RefCountedWithTracing : public Impl {
RefCountedPtr<Child> Ref(const DebugLocation& location,
const char* reason) GRPC_MUST_USE_RESULT {
if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count);
const RefCount::Value old_refs = refs_.get();
gpr_log(GPR_INFO, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s",
trace_flag_->name(), this, location.file(), location.line(),
old_refs, old_refs + 1, reason);
@ -157,14 +200,14 @@ class RefCountedWithTracing : public Impl {
// friend of this class.
void Unref() {
if (gpr_unref(&refs_)) {
if (refs_.Unref()) {
Delete(static_cast<Child*>(this));
}
}
void Unref(const DebugLocation& location, const char* reason) {
if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count);
const RefCount::Value old_refs = refs_.get();
gpr_log(GPR_INFO, "%s:%p %s:%d unref %" PRIdPTR " -> %" PRIdPTR " %s",
trace_flag_->name(), this, location.file(), location.line(),
old_refs, old_refs - 1, reason);
@ -185,9 +228,7 @@ class RefCountedWithTracing : public Impl {
: RefCountedWithTracing(static_cast<TraceFlag*>(nullptr)) {}
explicit RefCountedWithTracing(TraceFlag* trace_flag)
: trace_flag_(trace_flag) {
gpr_ref_init(&refs_, 1);
}
: trace_flag_(trace_flag) {}
#ifdef NDEBUG
explicit RefCountedWithTracing(DebugOnlyTraceFlag* trace_flag)
@ -195,17 +236,17 @@ class RefCountedWithTracing : public Impl {
#endif
// Note: Depending on the Impl used, this dtor can be implicitly virtual.
~RefCountedWithTracing() {}
~RefCountedWithTracing() = default;
private:
// Allow RefCountedPtr<> to access IncrementRefCount().
template <typename T>
friend class RefCountedPtr;
void IncrementRefCount() { gpr_ref(&refs_); }
void IncrementRefCount() { refs_.Ref(); }
TraceFlag* trace_flag_ = nullptr;
gpr_refcount refs_;
RefCount refs_;
};
} // namespace grpc_core

Loading…
Cancel
Save